00001 /***************************************************************************** 00002 * 00003 * $RCSfile: WayptEditForm_8c-source.html,v $ 00004 * 00005 * GPS4Palm Waypoint Edit Form 00006 * 00007 * This program is Copyright (C) 03/2003 Matthias Prinke 00008 * <matthias.prinke@surfeu.de> and covered by GNU's GPL. 00009 * In particular, this program is free software and comes WITHOUT 00010 * ANY WARRANTY. 00011 * 00012 * $Author: mp $ 00013 * 00014 * $Date: 2007-10-08 20:40:35 $ 00015 * 00016 * $Revision: 1.7.2.1 $ 00017 * 00018 * $Log: WayptEditForm_8c-source.html,v $ 00018 * Revision 1.7.2.1 2007-10-08 20:40:35 mp 00018 * updated for gps4palm V0.9.5 beta 00018 * 00019 * Revision 1.19 2005-03-25 13:33:55 mp 00020 * increased field_str buffer length 00021 * 00022 * Revision 1.18 2005/01/30 21:00:44 mp 00023 * corrected comment field truncation 00024 * 00025 * Revision 1.17 2005/01/29 10:22:26 mp 00026 * fixed comment 00027 * 00028 * Revision 1.16 2005/01/29 10:12:09 mp 00029 * added waypoint import from GeoDB 00030 * 00031 * Revision 1.15 2004/12/10 19:57:33 mp 00032 * replaced DmGet1Resource by DmGetResource and WayptEditSymScrl by 00033 * WayptEditPrevSymButton and WayptEditNextSymButton, 00034 * implemented clipboard, SysKeyboardDialog, and SysGraffitiReferenceDialog 00035 * 00036 * Revision 1.14 2004/12/09 17:26:19 mp 00037 * replaced default waypoint identifier/comment strings by string resources 00038 * 00039 * Revision 1.13 2004/11/27 10:16:57 mp 00040 * replaced ErrFatalDisplay() by Die() for memory allocation failure 00041 * 00042 * Revision 1.12 2004/11/24 21:28:14 mp 00043 * moved static function declarations from header to implementation file 00044 * 00045 * Revision 1.11 2004/11/23 17:46:31 mp 00046 * removed unused variable 00047 * 00048 * Revision 1.10 2004/11/16 20:44:18 mp 00049 * added check after creating new record, modified PackWaypoint() call 00050 * 00051 * Revision 1.9 2004/04/17 12:47:13 mp 00052 * modified waypoint display mode encoding according to Garmin I/O Spec 00053 * 00054 * Revision 1.8 2004/03/31 15:47:59 mp 00055 * added default waypoint display on frmOpenEvent 00056 * 00057 * Revision 1.7 2004/03/30 19:32:40 mp 00058 * added Waypoint Symbol selection and display 00059 * 00060 * Revision 1.6 2004/03/15 17:20:21 mp 00061 * added Waypoint Copy function 00062 * 00063 * Revision 1.5 2004/03/11 18:54:31 mp 00064 * fixed handling of sign (for DM/DMS and special cases) 00065 * 00066 * Revision 1.4 2004/03/10 17:35:57 mp 00067 * Modifications due to changes in Data.h, fixed UTM input. 00068 * 00069 * Revision 1.3 2004/03/09 19:12:35 mp 00070 * improved input field handling 00071 * 00072 * Revision 1.2 2004/03/08 20:26:44 mp 00073 * Added Proxmity Distance field, fixed Waypoint Identifier input, fixed 00074 * added handling of active field when WayptEditOkButton is pressed. 00075 * 00076 * Revision 1.1 2004/03/07 14:25:22 mp 00077 * initial version 00078 * 00079 * 00080 ****************************************************************************/ 00081 #include <PalmOS.h> 00082 #include "ResourceDefines.h" 00083 #include <Unix/sys_types.h> 00084 #include "stringil.h" 00085 #include "WayptEditForm.h" 00086 #include "GPS.h" /* ReadFromGPS() */ 00087 #include "Serial.h" 00088 #include "Utils.h" 00089 #include "Data.h" 00090 #include "utm.h" 00091 #include "geo.h" 00092 #include "geodb.h" 00093 #include "fp.h" 00094 #include "common.h" 00095 00096 #define WPT_X 90 00097 #define WPT_Y 30 00098 00099 /* Global Variables */ 00100 00101 /** store the location data with importGeoDBLocation() */ 00102 Location location; 00103 00104 extern PrefsType gPrefs; /* Preferences data structure */ 00105 extern DmOpenRef gWaypointDB; /* Waypoint Data Base reference */ 00106 extern GPSType gGPSData; /* GPS Data */ 00107 extern ActWayptType gSelWaypoint; /* Selected waypoint */ 00108 00109 00110 /* Static Functions */ 00111 static void WayptEditFormInit(void) WAYPTEDIT_SECTION; 00112 static Boolean scan_position(UInt16 fieldID, 00113 double *lat, double *lon) WAYPTEDIT_SECTION; 00114 static Boolean scan_zone(UInt16 *utm_zone, 00115 Char *utm_belt) WAYPTEDIT_SECTION; 00116 static void add_waypoint(double lat, double lon, 00117 UInt16 smbl) WAYPTEDIT_SECTION; 00118 static Boolean insert_position(double lat, double lon, 00119 double *eastP, double *northP) WAYPTEDIT_SECTION; 00120 static Boolean field_active(UInt16 fieldID) WAYPTEDIT_SECTION; 00121 static void select_symbol(UInt16 *sym, Int16 dir) WAYPTEDIT_SECTION; 00122 static Boolean geodb_str_to_deg(Location *loc, 00123 double *lat, double *lon) WAYPTEDIT_SECTION; 00124 00125 /***************************************************************************** 00126 * FUNCTION: WayptEditFormInit 00127 * 00128 * DESCRIPTION: Waypoint Edit Form Init Function (not used) 00129 * 00130 ****************************************************************************/ 00131 static 00132 void WayptEditFormInit(void) 00133 { 00134 00135 } 00136 00137 00138 /***************************************************************************** 00139 * FUNCTION: field_active 00140 * 00141 * DESCRIPTION: Determines if the specified field is active, i.e. has the 00142 * input focus. 00143 * 00144 * PARAMETERS: fieldID -- Field ID 00145 * 00146 * RETURNED: Status flag: specified field has focus 00147 ****************************************************************************/ 00148 static 00149 Boolean field_active(UInt16 fieldID) 00150 { 00151 FormPtr frmP = FrmGetActiveForm(); 00152 FieldAttrType fld_attr; 00153 00154 FldGetAttributes(FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, fieldID)), 00155 &fld_attr); 00156 00157 return (fld_attr.hasFocus == 1); 00158 } 00159 00160 00161 /***************************************************************************** 00162 * FUNCTION: scan_position 00163 * 00164 * DESCRIPTION: Scan position fields to latitude/longitude 00165 * depending on selevted position units. 00166 * 00167 * Note: The code assumes to run on a device with 00168 * latin character set. 00169 * Note: The degree sign '°' is named chrDegreeSign in 00170 * System/CharLatin.h (but we are sloppy...) 00171 * 00172 * GLOBALS: gPrefs -- Application Preferences 00173 * 00174 * PARAMETERS: fieldID -- ID of selected field 00175 * lat -- pointer to latitude 00176 * lon -- pointer to longitude 00177 * 00178 * RETURNED: Status flag: valid entry 00179 ****************************************************************************/ 00180 static 00181 Boolean scan_position(UInt16 fieldID, double *lat, double *lon) 00182 { 00183 FormPtr frmP; /* form ptr */ 00184 Char *strP; /* string ptr */ 00185 Char *trailP; /* trailing string ptr */ 00186 double tmp; /* temp. double */ 00187 short frac; /* number of fractional digits */ 00188 Int16 sign; /* sign */ 00189 00190 frmP = FrmGetActiveForm(); 00191 strP = FldGetTextPtr(FrmGetObjectPtr(frmP, 00192 FrmGetObjectIndex(frmP, fieldID))); 00193 00194 if (strP[0] == '-') { 00195 sign = -1; 00196 strP++; 00197 } else { 00198 sign = 1; 00199 } 00200 00201 /* first value is either angle in degrees or cartesian coordinate in meters */ 00202 tmp = cvt_atof(strP, &trailP, &frac); 00203 00204 /* handle degrees part or esting/northing */ 00205 switch (gPrefs.units.pos_unit) { 00206 case POS_D: 00207 /* 00208 * Field's contents considered as a single floating point number, 00209 * which may or may not end with a degree sign (but nothing else). 00210 */ 00211 if (*trailP == '\0' || *trailP == '°') { 00212 /* valid entry */ 00213 if (fieldID == LatitudeField) { 00214 /* Latitude */ 00215 if ((tmp > 90.0) || (tmp < -90.0)) { 00216 /* range error */ 00217 return false; 00218 } 00219 /* o.k., update position */ 00220 *lat = tmp * sign; 00221 00222 } else { 00223 /* Longitude */ 00224 if ((tmp > 180.0) || (tmp < -180.0)) { 00225 /* range error */ 00226 return false; 00227 } 00228 /* o.k., update position */ 00229 *lon = tmp * sign; 00230 00231 } 00232 return true; 00233 00234 } else { 00235 /* invalid entry */ 00236 return false; 00237 } 00238 break; 00239 00240 case POS_DM: 00241 case POS_DMS: 00242 /* 00243 * Field's contents must start with an integer number, 00244 * which must end with a degree sign. 00245 */ 00246 if (*trailP != '°' || frac > 0) { 00247 /* invalid entry */ 00248 return false; 00249 } else { 00250 /* valid entry */ 00251 if (fieldID == LatitudeField) { 00252 /* Latitude */ 00253 if ((tmp > 90.0) || (tmp < -90.0)) { 00254 /* range error */ 00255 return false; 00256 } 00257 /* o.k., update position */ 00258 *lat = tmp; 00259 00260 } else { 00261 /* Longitude */ 00262 if ((tmp > 180.0) || (tmp < -180.0)) { 00263 /* range error */ 00264 return false; 00265 } 00266 /* o.k., update position */ 00267 *lon = tmp; 00268 } 00269 } 00270 break; 00271 00272 case POS_UTM: 00273 /* 00274 * Field's contents must consist of a single floating point number only 00275 */ 00276 if (*trailP != '\0') { 00277 /* invalid entry */ 00278 return false; 00279 } 00280 if (fieldID == LatitudeField) { 00281 if ((tmp >= 100000.0) && (tmp <= 900000.0)) { 00282 *lat = tmp; 00283 return true; 00284 } else { 00285 return false; 00286 } 00287 } else { 00288 if ((tmp >= 0.0) && (tmp <= 10000000.0)) { 00289 *lon = tmp; 00290 return true; 00291 } else { 00292 return false; 00293 } 00294 } 00295 break; 00296 } /* switch (gPrefs.units.pos_unit) */ 00297 00298 /* skip degree sign */ 00299 strP = trailP + 1; 00300 00301 /* convert string to float */ 00302 tmp = cvt_atof(strP, &trailP, &frac); 00303 00304 /* 00305 * Handle minutes part 00306 * The following input is valid: 00307 * POS_DM: <mm.m>' 00308 * POS_DMS: <mm>' 00309 */ 00310 if (*trailP != '\'') { 00311 /* invalid entry */ 00312 return false; 00313 } 00314 00315 if (gPrefs.units.pos_unit == POS_DMS && frac > 0) { 00316 /* invalid entry */ 00317 return false; 00318 } 00319 if ((tmp >= 60.0) || (tmp < 0.0)) { 00320 /* range error */ 00321 return false; 00322 } 00323 00324 if (fieldID == LatitudeField) { 00325 /* o.k., update Latitude */ 00326 *lat += tmp/60.0; 00327 } else { 00328 /* o.k., update Longitude */ 00329 *lon += tmp/60.0; 00330 } 00331 00332 if (gPrefs.units.pos_unit == POS_DMS) { 00333 00334 /* skip minutes sign */ 00335 strP = trailP + 1; 00336 00337 /* convert string to float */ 00338 tmp = cvt_atof(strP, &trailP, NULL); 00339 00340 /* 00341 * Handle seconds part 00342 * The following input is valid: 00343 * <ss.s>" or <ss>" 00344 */ 00345 if (*trailP != '\"') { 00346 /* invalid entry */ 00347 return false; 00348 } 00349 if ((tmp >= 60.0) || (tmp < 0.0)) { 00350 /* range error */ 00351 return false; 00352 } 00353 if (fieldID == LatitudeField) { 00354 /* o.k., update Latitude */ 00355 *lat += tmp/3600.0; 00356 } else { 00357 /* o.k., update Longitude */ 00358 *lon += tmp/3600.0; 00359 } 00360 } /* if (gPrefs.units.pos_unit == POS_DMS) */ 00361 00362 if (fieldID == LatitudeField) { 00363 /* update sign of Latitude */ 00364 *lat = *lat * sign; 00365 } else { 00366 /* update sign of Longitude */ 00367 *lon = *lon * sign; 00368 } 00369 00370 return true; 00371 } 00372 00373 00374 /***************************************************************************** 00375 * FUNCTION: scan_zone 00376 * 00377 * DESCRIPTION: Scan zone field to UTM zone and belt, 00378 * update latitude and longitude 00379 * 00380 * PARAMETERS: eventP -- pointer to event structure 00381 * 00382 * RETURNED: Status flag: valid entry 00383 ****************************************************************************/ 00384 static 00385 Boolean scan_zone(UInt16 *utm_zone, Char *utm_belt) 00386 { 00387 FormPtr frmP; 00388 Char *strP; 00389 UInt16 zone; 00390 Char belt; 00391 00392 frmP = FrmGetActiveForm(); 00393 strP = FldGetTextPtr(FrmGetObjectPtr(frmP, 00394 FrmGetObjectIndex(frmP, ZoneField))); 00395 00396 if ((*strP >= '0') && (*strP <= '9')) { 00397 zone = *strP - '0'; 00398 strP++; 00399 } else { 00400 return false; 00401 } 00402 00403 if ((*strP >= '0') && (*strP <= '9')) { 00404 zone = zone * 10 + (*strP - '0'); 00405 strP++; 00406 } 00407 00408 if ((zone < 1) || (zone > 60)) { 00409 return false; 00410 } 00411 00412 belt = toupper(*strP); 00413 00414 if ((belt >= 'C') && (belt <= 'X') && 00415 (belt != 'I') && (belt != 'O')) { 00416 *utm_zone = zone; 00417 *utm_belt = belt; 00418 return true; 00419 } else { 00420 return false; 00421 } 00422 } 00423 00424 00425 /***************************************************************************** 00426 * FUNCTION: add_waypoint 00427 * 00428 * DESCRIPTION: Add new waypoint to database 00429 * 00430 * GLOBALS: gWaypointDB -- Waypoint Database Reference 00431 * 00432 * PARAMETERS: lat -- Latitude 00433 * lon -- Longitude 00434 * 00435 * RETURNED: % 00436 ****************************************************************************/ 00437 static 00438 void add_waypoint(double lat, double lon, UInt16 smbl) 00439 { 00440 FormPtr frmP; 00441 ListPtr lstP; 00442 waypoint_t waypoint; 00443 UInt16 len; 00444 Char *strP; 00445 UInt16 index; 00446 MemHandle h; 00447 float proxmity; 00448 00449 frmP = FrmGetActiveForm(); 00450 00451 /* Copy Identifier */ 00452 strP = FldGetTextPtr(FrmGetObjectPtr(frmP, 00453 FrmGetObjectIndex(frmP, IdentField))); 00454 len = StrLen(strP); 00455 MemSet((Char *)waypoint.ident, 6, 0); 00456 StrNCopy(waypoint.ident, strP, (len > 6) ? 6 : len); 00457 00458 /* Copy Latitude */ 00459 waypoint.posn.lat = deg2semi(lat); 00460 00461 /* Copy Longitude */ 00462 waypoint.posn.lon = deg2semi(lon); 00463 00464 /* Copy Proxmity Distance (no sanity check done!) */ 00465 strP = FldGetTextPtr(FrmGetObjectPtr(frmP, 00466 FrmGetObjectIndex(frmP, ProxField))); 00467 proxmity = cvt_atof(strP, NULL, NULL); 00468 proxmity = (proxmity < 0) ? 0 : proxmity; 00469 waypoint.dst = proxmity; 00470 00471 /* Copy Symbol */ 00472 waypoint.smbl = smbl; 00473 00474 /* Copy Display Mode */ 00475 lstP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, DisplayList)); 00476 switch ( LstGetSelection(lstP) ) { 00477 case 0: 00478 /* none */ 00479 waypoint.dspl = dspl_smbl_none; 00480 break; 00481 00482 case 1: 00483 /* symbol only */ 00484 waypoint.dspl = dspl_smbl_only; 00485 break; 00486 00487 case 2: 00488 /* with name */ 00489 waypoint.dspl = dspl_smbl_name; 00490 break; 00491 00492 case 3: 00493 /* with comment */ 00494 waypoint.dspl = dspl_smbl_cmnt; 00495 break; 00496 } 00497 00498 /* Copy Comment */ 00499 strP = FldGetTextPtr(FrmGetObjectPtr(frmP, 00500 FrmGetObjectIndex(frmP, CommentField))); 00501 StrCopy(waypoint.cmnt, strP); 00502 00503 /* Find sort position of new record in waypoint DB */ 00504 index = DmFindSortPosition(gWaypointDB, &waypoint, 0 /* newRecordInfo */, 00505 (DmComparF *)CompareWayptIdent /* DmComparF *compar */, 0 /* other */); 00506 00507 h = DmNewRecord(gWaypointDB, &index, 00508 1 /* size, will be set by PackWaypoint() */); 00509 00510 if (h) { 00511 DmReleaseRecord(gWaypointDB, index, false /* dirty */); 00512 } else { 00513 Die("Cannot create waypoint record!"); 00514 } 00515 00516 /* Pack Waypoint and store it in Database */ 00517 PackWaypoint(&waypoint, index); 00518 00519 } 00520 00521 00522 /***************************************************************************** 00523 * FUNCTION: insert_position 00524 * 00525 * DESCRIPTION: Insert position to fields 00526 * 00527 * GLOBALS: gPrefs -- Application Preferences 00528 * 00529 * PARAMETERS: lat -- Latitude 00530 * lon -- Longitude 00531 * eastP -- UTM Easting (ptr) 00532 * northP -- UTM Northing (ptr) 00533 * 00534 * RETURNED: flag -- Conversion to UTM successful. Always true, if any 00535 * position format other than UTM is set in the preferences. 00536 * If UTM position format is selected and the conversion is 00537 * successful, easting and northing are updated by eastP/northP. 00538 ****************************************************************************/ 00539 static 00540 Boolean insert_position(double lat, double lon, double *eastP, double *northP) 00541 { 00542 Char lat_str[20]; /* string buffer */ 00543 Char lon_str[20]; /* string buffer */ 00544 Char field_str[5]; /* string buffer */ 00545 Int32 err; /* error code */ 00546 Int32 zone; /* UTM Zone */ 00547 char hemisphere; /* 'N' / 'S' */ 00548 double easting; /* Easting in m */ 00549 double northing; /* Northing in m */ 00550 00551 switch (gPrefs.units.pos_unit) { 00552 case POS_D: 00553 /* Degrees */ 00554 format_number(lat, 7, lat_str); 00555 StrCat(lat_str, "°"); 00556 SetFieldText(LatitudeField, lat_str, false, true); 00557 00558 format_number(lon, 7, lon_str); 00559 StrCat(lon_str, "°"); 00560 SetFieldText(LongitudeField, lon_str, false, true); 00561 break; 00562 00563 case POS_DM: 00564 deg_to_dm_str(lat, lon, lat_str, lon_str); 00565 SetFieldText(LatitudeField, lat_str, false, true); 00566 SetFieldText(LongitudeField, lon_str, false, true); 00567 break; 00568 00569 case POS_DMS: 00570 deg_to_dms_str(lat, lon, lat_str, lon_str); 00571 SetFieldText(LatitudeField, lat_str, false, true); 00572 SetFieldText(LongitudeField, lon_str, false, true); 00573 break; 00574 00575 case POS_UTM: 00576 /* Universal Transverse Mercator - convert from lat/lon double values */ 00577 err = Convert_Geodetic_To_UTM ( 00578 deg2rad(lat) /* Latitude (rad) */, 00579 deg2rad(lon) /* Longitude (rad) */, 00580 &zone /* long *Zone */, 00581 &hemisphere /* Hemisphere */, 00582 &easting /* *Easting */, 00583 &northing /* *Northing */); 00584 00585 if (err == UTM_NO_ERROR) { 00586 /* print zone and belt to string */ 00587 StrPrintF(field_str, "%ld%c ", zone, Lat_To_UTM_Belt(lat)); 00588 SetFieldText(ZoneField, field_str, false, true); 00589 00590 /* print easting to string */ 00591 format_number(easting, 1, lat_str); 00592 SetFieldText(LatitudeField, lat_str, false, true); 00593 00594 /* print northing to string */ 00595 format_number(northing, 1, lon_str); 00596 SetFieldText(LongitudeField, lon_str, false, true); 00597 00598 /* return easting and northing */ 00599 *eastP = easting; 00600 *northP = northing; 00601 } else { 00602 return false; 00603 } 00604 break; 00605 } /* switch (gPrefs.units.pos_unit) */ 00606 00607 return true; 00608 } 00609 00610 00611 /***************************************************************************** 00612 * FUNCTION: select_symbol 00613 * 00614 * DESCRIPTION: Select waypoint symbol, show bitmap and string. 00615 * 00616 * PARAMETERS: sym -- Garmin symbol ID (ptr) 00617 * dir -- change direction (-1/0/+1) 00618 * 00619 * RETURNED: % 00620 ****************************************************************************/ 00621 static 00622 void select_symbol(UInt16 *sym, Int16 dir) 00623 { 00624 FormPtr frmP; /* form ptr */ 00625 MemHandle resH; /* resource handle */ 00626 BitmapType *bmpP; /* bitmap ptr */ 00627 RectangleType rect; /* rectangle */ 00628 UInt16 wpt_smbl; /* waypt. symbol ID (Garmin)*/ 00629 UInt16 smbl; /* waypt. symbol ID (OS) */ 00630 00631 frmP = FrmGetActiveForm(); 00632 wpt_smbl = *sym; 00633 wpt_smbl += dir; 00634 00635 /* skip 'holes' */ 00636 switch (wpt_smbl) { 00637 case sym_mob+1: 00638 wpt_smbl = sym_boat_ramp; 00639 break; 00640 00641 case sym_boat_ramp-1: 00642 wpt_smbl = sym_mob; 00643 break; 00644 00645 case sym_circle_x+1: 00646 wpt_smbl = sym_is_hwy; 00647 break; 00648 00649 case sym_is_hwy-1: 00650 wpt_smbl = sym_circle_x; 00651 break; 00652 00653 case sym_border+1: 00654 wpt_smbl = sym_airport; 00655 break; 00656 00657 case sym_airport-1: 00658 wpt_smbl = sym_border; 00659 break; 00660 } 00661 00662 /* update symbol ID */ 00663 *sym = wpt_smbl; 00664 00665 /* adjust PalmOS ID to Garmin ID */ 00666 smbl = (wpt_smbl >= 16383) ? wpt_smbl-16000 : wpt_smbl; 00667 00668 /* get bitmap resource */ 00669 resH = DmGetResource('Tbmp', smbl); 00670 00671 /* use default if symbol unavailable */ 00672 if (!resH) { 00673 resH = DmGetResource('Tbmp', WayptDefBmp); 00674 } 00675 00676 /* draw bitmap */ 00677 if (resH) { 00678 RctSetRectangle(&rect, WPT_X-1, WPT_Y-1, 16 /* w */, 14 /* h */); 00679 WinEraseRectangle(&rect, 0 /* cornerDiam */ ); 00680 bmpP = MemHandleLock(resH); 00681 WinDrawBitmap(bmpP, WPT_X, WPT_Y); 00682 MemHandleUnlock(resH); 00683 DmReleaseResource(resH); 00684 } 00685 00686 /* get string resource */ 00687 resH = DmGetResource('tSTR', smbl); 00688 00689 /* use default if symbol string unavailable */ 00690 if (!resH) { 00691 resH = DmGetResource('tSTR', WayptDefStr); 00692 } 00693 00694 /* update field */ 00695 if (resH) { 00696 FldSetTextHandle(FrmGetObjectPtr(frmP, 00697 FrmGetObjectIndex(frmP, WayptEditSymField)), resH); 00698 FldDrawField(FrmGetObjectPtr(frmP, 00699 FrmGetObjectIndex(frmP, WayptEditSymField))); 00700 /* Note: resH still in use by field! */ 00701 /* DmReleaseResource(resH); */ 00702 } 00703 } 00704 00705 00706 /****************************************************************************/ 00707 /** 00708 * \brief Convert GeoDB location strings to Latitude/Longitude 00709 * 00710 * \note This function has been adapted from scan_position() 00711 * 00712 * \param loc GeoDB location structure 00713 * \param lat latitude returned by reference 00714 * \param lon longitude returned by reference 00715 * 00716 ****************************************************************************/ 00717 static 00718 Boolean geodb_str_to_deg(Location *loc, double *lat, double *lon) 00719 { 00720 Char *trailP; /* trailing string ptr */ 00721 Char *strP; /* string ptr */ 00722 double tmp; /* temp. double */ 00723 short frac; /* number of fractional digits */ 00724 00725 /* Convert Latitude */ 00726 00727 /* first value is angle in degrees */ 00728 tmp = cvt_atof(loc->latStr, &trailP, &frac); 00729 00730 /* 00731 * Field's contents must start with an integer number, 00732 * which must end with a colon. 00733 */ 00734 if (*trailP != ':' || frac > 0) { 00735 /* invalid entry */ 00736 return false; 00737 } else { 00738 00739 if ((tmp > 90.0) || (tmp < 0.0)) { 00740 /* range error */ 00741 return false; 00742 } 00743 /* o.k., update position */ 00744 *lat = tmp; 00745 00746 } 00747 00748 /* Handle minutes part */ 00749 /* skip degree sign/colon */ 00750 strP = trailP + 1; 00751 00752 /* convert string to float */ 00753 tmp = cvt_atof(strP, &trailP, &frac); 00754 00755 if ((tmp >= 60.0) || (tmp < 0.0)) { 00756 /* range error */ 00757 return false; 00758 } 00759 00760 *lat += tmp/60.0; 00761 00762 00763 /* Convert Longitude */ 00764 00765 /* first value is angle in degrees */ 00766 tmp = cvt_atof(loc->longStr, &trailP, &frac); 00767 00768 00769 /* 00770 * Field's contents must start with an integer number, 00771 * which must end with a colon. 00772 */ 00773 if (*trailP != ':' || frac > 0) { 00774 /* invalid entry */ 00775 return false; 00776 } else { 00777 00778 if ((tmp > 180.0) || (tmp < 0.0)) { 00779 /* range error */ 00780 return false; 00781 } 00782 /* o.k., update position */ 00783 *lon = tmp; 00784 } 00785 00786 /* Handle minutes part */ 00787 /* skip degree sign/colon */ 00788 strP = trailP + 1; 00789 00790 /* convert string to float */ 00791 tmp = cvt_atof(strP, &trailP, &frac); 00792 00793 if ((tmp >= 60.0) || (tmp < 0.0)) { 00794 /* range error */ 00795 return false; 00796 } 00797 00798 *lon += tmp/60.0; 00799 00800 /* adjust signs */ 00801 *lat = (loc->latNS) ? *lat : *lat * -1.0; 00802 *lon = (loc->longEW) ? *lon : *lon * -1.0; 00803 00804 /* success */ 00805 return true; 00806 } 00807 00808 00809 /****************************************************************************/ 00810 /** 00811 * \brief Waypoint Edit Form Event Handler 00812 * 00813 * GLOBALS: gPrefs Application Preferences 00814 * 00815 * \param eventP pointer to event structure 00816 * 00817 * \return Status flag: event handled 00818 ****************************************************************************/ 00819 Boolean WayptEditFormHandleEvent(EventPtr eventP) 00820 { 00821 Boolean handled; /* flag: event handled */ 00822 FormPtr frmP; /* form ptr */ 00823 ListPtr lstP; /* list ptr */ 00824 FieldPtr fldP; /* field ptr */ 00825 UInt16 sel; /* list selection */ 00826 UInt16 rec; /* record index */ 00827 packed_waypoint_t *packed_waypoint; /* packed waypoint ptr */ 00828 waypoint_t waypoint; /* unpacked waypoint */ 00829 MemHandle waypointDBEntry; /* waypoint record handle */ 00830 static double lat; /* latitude */ 00831 static double lon; /* longitude */ 00832 static UInt16 utm_zone = 32; /* UTM zone */ 00833 static char utm_belt = 'U'; /* UTM belt */ 00834 static Char tmp[20]; /* temp. string buffer */ 00835 static Boolean lat_valid; /* latitude valid */ 00836 static Boolean lon_valid; /* longitude valid */ 00837 Boolean valid; /* input valid */ 00838 UInt16 fld_focus; /* ID of active field */ 00839 static UInt16 fld_focus_old; /* ID of previously act field */ 00840 static UInt16 wpt_smbl; /* waypoint symbol ID (Gar.) */ 00841 Int16 dir; /* waypoint change direction */ 00842 Err err; /* UTM error */ 00843 00844 frmP = FrmGetActiveForm(); 00845 handled = false; 00846 00847 /* 00848 * The fields' contents have to be checked whenever a field looses focus. 00849 * Unfortunately, there is no appropriate event (ctlExitEvent is not triggered 00850 * by fields). So we have to track the active field manually. 00851 */ 00852 if ( field_active(LatitudeField) ) { 00853 fld_focus = LatitudeField; 00854 } else if ( field_active(LongitudeField) ) { 00855 fld_focus = LongitudeField; 00856 } else if ( field_active(ZoneField) ) { 00857 fld_focus = ZoneField; 00858 } else { 00859 /* none */ 00860 fld_focus = 0; 00861 } 00862 00863 if ((fld_focus_old != 0) && (fld_focus != fld_focus_old)) { 00864 /* Pseudo-fldExitEvent */ 00865 switch (fld_focus_old) { 00866 case LatitudeField: 00867 valid = scan_position(LatitudeField, &lat, &lon); 00868 00869 if (valid) { 00870 lat_valid = true; 00871 } else { 00872 /* restore old text */ 00873 SetFieldText(LatitudeField, tmp, false /* append */, 00874 true /* redraw */); 00875 } 00876 break; 00877 00878 case LongitudeField: 00879 valid = scan_position(LongitudeField, &lat, &lon); 00880 00881 if (valid) { 00882 lon_valid = true; 00883 } else { 00884 /* restore old text */ 00885 SetFieldText(LongitudeField, tmp, false /* append */, 00886 true /* redraw */); 00887 } 00888 break; 00889 00890 case ZoneField: 00891 valid = scan_zone(&utm_zone, &utm_belt); 00892 00893 if (!valid) { 00894 /* restore old text */ 00895 SetFieldText(ZoneField, tmp, false /* append */, 00896 true /* redraw */); 00897 } 00898 break; 00899 00900 } 00901 } 00902 00903 switch (eventP->eType) { 00904 case frmOpenEvent: 00905 WayptEditFormInit(); 00906 FrmDrawForm(frmP); 00907 00908 lat_valid = lon_valid = false; 00909 00910 /* show objects depending on selected position units */ 00911 if (gPrefs.units.pos_unit == POS_UTM) { 00912 FrmShowObject(frmP, FrmGetObjectIndex(frmP, ZoneLabel)); 00913 FrmShowObject(frmP, FrmGetObjectIndex(frmP, ZoneField)); 00914 FrmShowObject(frmP, FrmGetObjectIndex(frmP, EastLabel)); 00915 FrmShowObject(frmP, FrmGetObjectIndex(frmP, NorthLabel)); 00916 } else { 00917 FrmShowObject(frmP, FrmGetObjectIndex(frmP, LatLabel)); 00918 FrmShowObject(frmP, FrmGetObjectIndex(frmP, LonLabel)); 00919 } 00920 00921 if (gSelWaypoint.valid) { 00922 /* write selected waypoint data to fields */ 00923 /* Note: Waypoint Symbol will be lost */ 00924 err = DmFindRecordByID(gWaypointDB, gSelWaypoint.waypointID, 00925 &rec); 00926 00927 if (!err) { 00928 /* active waypoint found */ 00929 waypointDBEntry = DmQueryRecord(gWaypointDB, rec); 00930 packed_waypoint = 00931 (packed_waypoint_t *)MemHandleLock(waypointDBEntry); 00932 UnpackWaypoint(&waypoint, packed_waypoint); 00933 00934 /* copy waypoint ID */ 00935 MemSet((Char *)tmp, 7, 0); 00936 StrNCopy(tmp, (Char *)&waypoint.ident, 6); 00937 SetFieldText(IdentField, tmp, false, true); 00938 00939 /* copy comment */ 00940 SetFieldText(CommentField, waypoint.cmnt, false, true); 00941 format_number(waypoint.dst, 0, tmp); 00942 00943 /* copy proximity distance */ 00944 SetFieldText(ProxField, tmp, false, true); 00945 00946 /* set display mode pop-up selection */ 00947 switch (waypoint.dspl) { 00948 case dspl_smbl_none: 00949 /* none */ 00950 sel = 0; 00951 break; 00952 00953 case dspl_smbl_only: 00954 /* symbol only */ 00955 sel = 1; 00956 break; 00957 00958 case dspl_smbl_name: 00959 /* with name */ 00960 sel = 2; 00961 break; 00962 00963 case dspl_smbl_cmnt: 00964 /* with comment */ 00965 sel = 3; 00966 break; 00967 00968 default: 00969 /* symbol only */ 00970 sel = 1; 00971 break; 00972 } 00973 lstP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, DisplayList)); 00974 LstSetSelection (lstP, sel); 00975 CtlSetLabel(FrmGetObjectPtr(frmP, 00976 FrmGetObjectIndex(frmP, DisplayPopup)), 00977 LstGetSelectionText(lstP, sel)); 00978 00979 /* draw waypoint symbol */ 00980 wpt_smbl = waypoint.smbl; 00981 select_symbol(&wpt_smbl, 0 /* dir */); 00982 00983 /* Insert current position to fields */ 00984 if (insert_position(semi2deg(waypoint.posn.lat), 00985 semi2deg(waypoint.posn.lon), &lat, &lon)) { 00986 if (gPrefs.units.pos_unit == POS_UTM) { 00987 /* easting/northing returned in lat/lon ! */ 00988 /* get UTM field */ 00989 scan_zone(&utm_zone, &utm_belt); 00990 } else { 00991 lat = semi2deg(waypoint.posn.lat); 00992 lon = semi2deg(waypoint.posn.lon); 00993 } 00994 lat_valid = true; 00995 lon_valid = true; 00996 } 00997 MemHandleUnlock(waypointDBEntry); 00998 } 00999 01000 } else { 01001 /* write templates to fields */ 01002 MemHandle strH; /* string handle */ 01003 MemPtr strP; /* string ptr */ 01004 01005 /* get string from resource */ 01006 strH = DmGetResource(strRsc, WptIdentStr); 01007 01008 if (strH != NULL) { 01009 /* string handle valid, lock it */ 01010 strP = MemHandleLock(strH); 01011 01012 SetFieldText(IdentField, strP, false, true); 01013 01014 /* unlock string handle */ 01015 MemHandleUnlock(strH); 01016 01017 /* release string resource */ 01018 DmReleaseResource(strH); 01019 } 01020 01021 strH = DmGetResource(strRsc, WptCmntStr); 01022 01023 if (strH != NULL) { 01024 /* string handle valid, lock it */ 01025 strP = MemHandleLock(strH); 01026 01027 SetFieldText(CommentField, strP, false, true); 01028 01029 /* unlock string handle */ 01030 MemHandleUnlock(strH); 01031 01032 /* release string resource */ 01033 DmReleaseResource(strH); 01034 } 01035 01036 SetFieldText(ProxField, "1000.0", false, true); 01037 01038 switch (gPrefs.units.pos_unit) { 01039 case POS_D: 01040 SetFieldText(LatitudeField, "DD.DDDDDDD°", false, true); 01041 SetFieldText(LongitudeField, "DDD.DDDDDDD°", false, true); 01042 break; 01043 01044 case POS_DM: 01045 SetFieldText(LatitudeField, "DD°MM.MMMM\'", false, true); 01046 SetFieldText(LongitudeField, "DDD°MM.MMMM\'", false, true); 01047 break; 01048 01049 case POS_DMS: 01050 SetFieldText(LatitudeField, "DD°MM\'SS.SSS\"", false, true); 01051 SetFieldText(LongitudeField, "DDD°MM\'SS.SSS\"", false, true); 01052 break; 01053 01054 case POS_UTM: 01055 SetFieldText(ZoneField, "32U", false, true); 01056 SetFieldText(LatitudeField, "EEEEEE.E", false, true); 01057 SetFieldText(LongitudeField, "NNNNNNN.N", false, true); 01058 break; 01059 } 01060 01061 /* set default pop-up selection */ 01062 lstP = FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, DisplayList)); 01063 LstSetSelection (lstP, 1 /* sel */); 01064 CtlSetLabel(FrmGetObjectPtr(frmP, FrmGetObjectIndex(frmP, DisplayPopup)), 01065 LstGetSelectionText(lstP, 1 /* sel */)); 01066 01067 /* draw waypoint symbol */ 01068 wpt_smbl = WayptDefBmp; 01069 select_symbol(&wpt_smbl, 0 /* dir */); 01070 01071 } 01072 handled = true; 01073 break; 01074 01075 case menuEvent: 01076 /* check if any field has focus */ 01077 if ( field_active(IdentField) || 01078 field_active(CommentField) || 01079 field_active(LatitudeField) || 01080 field_active(LongitudeField) || 01081 field_active(ProxField)) { 01082 fldP = (FieldPtr)FrmGetObjectPtr(frmP, FrmGetFocus(frmP)); 01083 handled = true; 01084 } else { 01085 fldP = NULL; 01086 } 01087 01088 switch (eventP->data.menu.itemID) { 01089 case UndoMenu: 01090 if (fldP) 01091 FldUndo(fldP); 01092 break; 01093 01094 case CutMenu: 01095 if (fldP) 01096 FldCut(fldP); 01097 break; 01098 01099 case CopyMenu: 01100 if (fldP) 01101 FldCopy(fldP); 01102 break; 01103 01104 case PasteMenu: 01105 if (fldP) 01106 FldPaste(fldP); 01107 break; 01108 01109 case KeyboardMenu: 01110 if ( field_active(IdentField) || field_active(CommentField) ) { 01111 SysKeyboardDialog(kbdAlpha); 01112 } else if ( field_active(LatitudeField) || 01113 field_active(LongitudeField) || 01114 field_active(ProxField) ) { 01115 SysKeyboardDialog(kbdNumbersAndPunc); 01116 } 01117 handled = true; 01118 break; 01119 01120 case GraffitiMenu: 01121 SysGraffitiReferenceDialog(referenceDefault); 01122 handled = true; 01123 break; 01124 01125 } /* switch (eventP->data.menu.itemID) */ 01126 break; 01127 01128 case fldEnterEvent: 01129 switch (eventP->data.ctlSelect.controlID) { 01130 case LatitudeField: 01131 /* 01132 * save contents, we might have to restore it 01133 * if the new input is invalid 01134 */ 01135 if (fld_focus_old != LatitudeField) { 01136 StrCopy(tmp, FldGetTextPtr(FrmGetObjectPtr(frmP, 01137 FrmGetObjectIndex(frmP, LatitudeField)))); 01138 } 01139 break; 01140 01141 case LongitudeField: 01142 /* 01143 * save contents, we might have to restore it 01144 * if the new input is invalid 01145 */ 01146 if (fld_focus_old != LongitudeField) { 01147 StrCopy(tmp, FldGetTextPtr(FrmGetObjectPtr(frmP, 01148 FrmGetObjectIndex(frmP, LongitudeField)))); 01149 } 01150 break; 01151 01152 case ZoneField: 01153 /* 01154 * save contents, we might have to restore it 01155 * if the new input is invalid 01156 */ 01157 if (fld_focus_old != ZoneField) { 01158 StrCopy(tmp, FldGetTextPtr(FrmGetObjectPtr(frmP, 01159 FrmGetObjectIndex(frmP, ZoneField)))); 01160 } 01161 break; 01162 01163 } 01164 break; 01165 01166 case keyDownEvent: 01167 switch (eventP->data.keyDown.chr) { 01168 01169 case pageUpChr: 01170 dir = 0; 01171 /* increment */ 01172 if (wpt_smbl == sym_seaplane) { 01173 wpt_smbl = sym_anchor; 01174 } else { 01175 dir = 1; 01176 } 01177 select_symbol(&wpt_smbl, dir); 01178 handled = true; 01179 break; 01180 01181 case pageDownChr: 01182 dir = 0; 01183 /* decrement */ 01184 if (wpt_smbl == 0) { 01185 wpt_smbl = sym_seaplane; /* wrap around */ 01186 } else { 01187 dir = -1; 01188 } 01189 select_symbol(&wpt_smbl, dir); 01190 handled = true; 01191 break; 01192 } 01193 break; 01194 01195 case ctlSelectEvent: 01196 switch (eventP->data.ctlSelect.controlID) { 01197 01198 case WayptEditOkButton: 01199 switch (fld_focus) { 01200 case LatitudeField: 01201 /* Latitude field is still active, get contents */ 01202 valid = scan_position(LatitudeField, &lat, &lon); 01203 01204 if (valid) { 01205 lat_valid = true; 01206 } else { 01207 /* restore old text */ 01208 SetFieldText(LatitudeField, tmp, false /* append */, 01209 true /* redraw */); 01210 } 01211 break; 01212 01213 case LongitudeField: 01214 valid = scan_position(LongitudeField, &lat, &lon); 01215 01216 if (valid) { 01217 lon_valid = true; 01218 } else { 01219 /* restore old text */ 01220 SetFieldText(LongitudeField, tmp, false /* append */, 01221 true /* redraw */); 01222 } 01223 break; 01224 01225 case ZoneField: 01226 valid = scan_zone(&utm_zone, &utm_belt); 01227 01228 if (!valid) { 01229 /* restore old text */ 01230 SetFieldText(ZoneField, tmp, false /* append */, 01231 true /* redraw */); 01232 } 01233 break; 01234 01235 default: 01236 valid = true; 01237 break; 01238 } /* switch (fld_focus) */ 01239 01240 if (gPrefs.units.pos_unit == POS_UTM) { 01241 /* lat and lon actually contain easting and northing! */ 01242 double easting = lat; 01243 double northing = lon; 01244 01245 err = Convert_UTM_To_Geodetic(utm_zone, 01246 (utm_belt >= 'N') ? 'N' : 'S' /* Hemisphere */, 01247 easting, 01248 northing, 01249 &lat, 01250 &lon); 01251 01252 if (err != UTM_NO_ERROR) { 01253 break; 01254 } 01255 01256 lat = rad2deg(lat); 01257 lon = rad2deg(lon); 01258 } 01259 01260 if (lat_valid & lon_valid) { 01261 /* add waypoint and close form only if fields are valid */ 01262 add_waypoint(lat, lon, wpt_smbl); 01263 FrmGotoForm(WaypointForm); 01264 } 01265 handled = true; 01266 break; 01267 01268 case WayptEditCancelButton: 01269 /* close form without changing database */ 01270 FrmGotoForm(WaypointForm); 01271 handled = true; 01272 break; 01273 01274 case WayptEditHereButton: 01275 /* insert current position */ 01276 01277 /* throw away anything in the buffer-- we want fresh data */ 01278 DoReceiveFlush(gPortID, 1); 01279 01280 /* get new data */ 01281 ReadFromGPS(); 01282 01283 if (!gGPSData.valid) 01284 break; 01285 01286 if (fld_focus != 0) { 01287 /* release focus from active field */ 01288 FldReleaseFocus(FrmGetObjectPtr(frmP, 01289 FrmGetObjectIndex(frmP, fld_focus))); 01290 fld_focus = 0; 01291 } 01292 01293 /* Insert current position to fields */ 01294 if (insert_position(gGPSData.lat, gGPSData.lon, &lat, &lon)) { 01295 if (gPrefs.units.pos_unit == POS_UTM) { 01296 /* easting/northing returned in lat/lon ! */ 01297 /* get UTM field */ 01298 scan_zone(&utm_zone, &utm_belt); 01299 } else { 01300 lat = gGPSData.lat; 01301 lon = gGPSData.lon; 01302 } 01303 lat_valid = true; 01304 lon_valid = true; 01305 } 01306 01307 handled = true; 01308 break; 01309 01310 case WayptEditImportButton: 01311 /* get GeoDB data */ 01312 if ( importGeoDBLocation() ) { 01313 Char tempStr[80]; /* string buffer */ 01314 Int dls; /* daylight saving time array index */ 01315 CharPtr dlsList[] = { 01316 "No", "Yes", "Australia", "Europe", 01317 "N.America", "S.America", "User Defined" 01318 }; 01319 01320 /* Convert GeoDB strings to double Latitude and Longitude */ 01321 if ( geodb_str_to_deg(&location, &lat, &lon) ) { 01322 01323 /* Insert current position to fields */ 01324 if (insert_position(lat, lon, &lat, &lon)) { 01325 01326 if (gPrefs.units.pos_unit == POS_UTM) { 01327 /* easting/northing returned in lat/lon ! */ 01328 /* get UTM field */ 01329 scan_zone(&utm_zone, &utm_belt); 01330 } 01331 lat_valid = true; 01332 lon_valid = true; 01333 } 01334 } 01335 01336 /* add Name */ 01337 if (StrLen(location.name)) { 01338 StrPrintF(tempStr, "%s;",location.name); 01339 } 01340 01341 /* add Altitude */ 01342 if (StrLen(location.altStr)) { 01343 StrPrintF(&tempStr[StrLen(tempStr)], 01344 "Alt: %s;", location.altStr); 01345 } 01346 01347 /* add GMT Offset */ 01348 if (StrLen(location.gmtStr)) { 01349 StrPrintF(&tempStr[StrLen(tempStr)], "GMT Offset: %s %s;", 01350 location.gmtStr, (CharPtr)(location.gmtEW?"E":"W")); 01351 } 01352 01353 /* add Daylight Saving Time */ 01354 01355 /* high bit set when daylight time */ 01356 StrPrintF(&tempStr[StrLen(tempStr)], "DST: %s ", 01357 location.dayLight & 0x80?"ST":"DT"); 01358 01359 dls = location.dayLight & 0x7f; // display DayLight rule 01360 01361 if (dls <8) { 01362 StrCopy(&tempStr[StrLen(tempStr)], dlsList[dls]); 01363 } else { 01364 StrCopy(&tempStr[StrLen(tempStr)], "DLS Error"); 01365 } 01366 01367 /* truncate to Garmin Comment Field width */ 01368 tempStr[39] = '\0'; 01369 01370 /* set Comment Field*/ 01371 SetFieldText(CommentField, tempStr, false, true); 01372 01373 } else { 01374 FrmAlert(GeodbImportAlert); 01375 } 01376 handled = true; 01377 break; 01378 01379 case WayptEditPrevSymButton: 01380 dir = 0; 01381 /* increment */ 01382 if (wpt_smbl == sym_seaplane) { 01383 wpt_smbl = sym_anchor; 01384 } else { 01385 dir = 1; 01386 } 01387 select_symbol(&wpt_smbl, dir); 01388 handled = true; 01389 break; 01390 01391 case WayptEditNextSymButton: 01392 dir = 0; 01393 /* decrement */ 01394 if (wpt_smbl == 0) { 01395 wpt_smbl = sym_seaplane; /* wrap around */ 01396 } else { 01397 dir = -1; 01398 } 01399 select_symbol(&wpt_smbl, dir); 01400 handled = true; 01401 break; 01402 } 01403 break; 01404 01405 case frmCloseEvent: 01406 /* no active field */ 01407 fld_focus = fld_focus_old = 0; 01408 01409 /* Deallocate Fields' Text Memory */ 01410 SetFieldText(IdentField, NULL, false, true); 01411 FldSetTextHandle(FrmGetObjectPtr(frmP, 01412 FrmGetObjectIndex(frmP, WayptEditSymField)), NULL); 01413 if (gPrefs.units.pos_unit == POS_UTM) { 01414 SetFieldText(ZoneField, NULL, false, true); 01415 } 01416 SetFieldText(LatitudeField, NULL, false, true); 01417 SetFieldText(LongitudeField, NULL, false, true); 01418 SetFieldText(ProxField, NULL, false, true); 01419 SetFieldText(CommentField, NULL, false, true); 01420 break; 01421 } 01422 01423 /* save current focus */ 01424 fld_focus_old = fld_focus; 01425 01426 return(handled); 01427 } /* WayptEditFormHandleEvent() */