datalogExtract.sml

  Download

More scripts: Advanced

Syntax Highlighing:

comments, key words, predefined symbols, class members & methods, functions & classes
            
#------------------------------------------------------------------------
#
#	DATALOG.SML
#
# Updated 9 April 2006.  Requires use of TNTmips2006:72
#
#########################################################################
#									CONFIGURATION SECTION
# Enter the path to your starting layout
# If the script is in an RVC file, assume all the data
# is in that file.  If it's not, assume I'm still working
# on it and get the data from my data directory
string datafile$, layoutfile$, layoutname$;
if (_context.ScriptIsRVCObject) {
	datafile$ = _context.Filename;
	layoutfile$ = _context.ScriptDir + "datalog.rvc";
	layoutname$ = "SPOT_Start";
	}
else {
	datafile$ = _context.ScriptDir + "datalg.rvc";
	layoutfile$ = _context.ScriptDir + "Stacks.rvc";
	layoutname$ = "SPOT_Start";
	}
if (!fexists(layoutfile$)) layoutfile$ = "";
#layoutfile$ = "";
#----------------------------------------------------
#  The projection of the pinmap layer is set here
class SR_COORDREFSYS PinMapCRS, LatLonCRS;
PinMapCRS.Create("1200", "2014", "25296");
LatLonCRS.Create("1280", "2800");
#class MapProj PinMapProj, LatLonProj;
#PinMapProj.System = "UTM";
#PinMapProj.Ellipsoid = "Clarke 1866";
#PinMapProj.Zone = "18";
# This projection is used for the view position report
#LatLonProj.System = "Latitude / Longitude";
#LatLonProj.Datum = "World Geodetic System 1984";
#LatLonProj.Ellipsoid = "WGS 1984";
#------------------------------------------------------------------------
#							END OF CONFIGURATION SECTION
#########################################################################
#
#	Declare variables which we'll need later
#
class COLOR icon_color, tipcolor, defaultTipColor;
class XmForm form, barform;
raster Composite;
class PointTool point_tool;
class GRE_VIEW view;
class GRE_GROUP group;
class GRE_LAYER_RASTER layer;
class GRE_LAYOUT layout;
class GRE_LAYER_PINMAP MasterLayer;
class POINT2D pt;
class POINT3D pt3;
class ToolTip helptip0, helptip1, helptip2, helptip3; 
class ToolTip helptip4, helptip5, helptip6, helptip7;
class PushButtonItem showfeaturesicon;
class DATABASE MasterDBase;
class DBTABLEINFO MasterDBTInfo, tinfo;
class GPSPort gpsport;
numeric gpsset = 0;
numeric editRecNum = 0;
numeric layerIDNum = 0;
numeric inPointTool = 0;
numeric tipDelay = 0;
numeric gpsOffScreen = 0;
string tipgroup$, lasttipgroup$;
#--------------------------------------------------------------
#	Read all the settings for a single help tip out of the
#	helptips.txt resource.
proc SetTip(class INIHANDLE ini, class ToolTip tip, tipgroup$, name$) {
	local string dftcolor$ = IniReadString(tipgroup$, "Color");
	local string color$;
	local numeric duration;
	tipgroup$ = IniReadString(tipgroup$, name$);
	tip.Disabled = 1;	 # We'll reenable it, resetting it's timer later
	if (tipgroup$ != "") {
		tip.String = IniReadString(tipgroup$, "Tip");
		color$ = IniReadString(tipgroup$, "Color");
		if (color$ == "") color$ = dftcolor$;
		if (color$ == "") {
			tip.BackgroundColor = defaultTipColor;
			}
		else {
			tipcolor.Name = color$;
			tip.BackgroundColor = tipcolor;
			# The following will work shortly after 6.0 ships
			#tip.BackgroundColor.Name = color$;
			}
		duration = IniReadNumber(tipgroup$, "Duration", 5);
		tip.Delay = tipDelay * 1000;	# Stored in seconds, tips want milliseconds
		tipDelay += duration;			# delay for next tip
		tip.Disabled = 0;
		}
	}
numeric lastnearpt;
proc SetHelpTip(tracking) {
	local numeric nearpt, dist;
	local class INIHANDLE ini;
	pt = ViewTransPointViewToLayer(view, MasterLayer, point_tool.point);
	if (tracking == -1 || !inPointTool) {
		tipgroup$ = "NoTips";
		nearpt = 0;
		}
	else if (!gpsport || GPSNumSources() < 1 || gpsport.Status != "Good") {
		tipgroup$ = "GPSNoSource";
		}
	else if (gpsOffScreen) {
		tipgroup$ = "GPSOffScreen";
		}
	else if (tracking) {
		tipgroup$ = "GPSTrackingOn";
		}
	else {
		tipgroup$ = "GPSTrackingOff";
		}
	if (tracking != -1) {
		nearpt = (point_tool.HasPosition && PinmapLayerFindClosest(MasterLayer, pt, 50, dist) > 0);
		}
	if (tipgroup$ != lasttipgroup$ || nearpt != lastnearpt) {
		lasttipgroup$ = tipgroup$;
		lastnearpt = nearpt;
		ini = IniOpenScriptResource("helptips.txt");
		tipDelay = 2;	# 2 seconds before first tip shows
		if (nearpt) {
			SetTip(ini, helptip0, "ToolNearPoint", "1");
			}
		else {
			helptip0.Disabled = 1;
			}
		SetTip(ini, helptip1, tipgroup$, "1");
		SetTip(ini, helptip2, tipgroup$, "2");
		SetTip(ini, helptip3, tipgroup$, "3");
		SetTip(ini, helptip4, tipgroup$, "4");
		SetTip(ini, helptip5, tipgroup$, "5");
		SetTip(ini, helptip6, tipgroup$, "6");
		SetTip(ini, helptip7, tipgroup$, "7");
		IniClose(ini);
		}
	}
#--------------------------------------------------------------
# Check to see if the GPS is on screen or not.  Set or clear
# gpsOffScreen 
proc CheckGPS() {
#	pt = TransPoint2D(gpsport.LastData.position, ViewGetTransMapToView(view, LatLonProj));
	pt = TransPoint2D(gpsport.LastData.position, ViewGetTransMapToView(view, LatLonCRS));
	pt = TransPoint2D(pt, ViewGetTransViewToScreen(view));
	gpsOffScreen = 0;
	if (pt.x < 0 || pt.y < 0 || pt.x >= view.DrawingArea.Width || pt.y >= view.DrawingArea.Height) {
		gpsOffScreen = 1;
		}
	}
#--------------------------------------------------------------
# Function to call on GPS poll (once a second, moving or not)
proc CB_GPSPoll() {
# Set gpsOffScreen to 1 if it's off the screen
	CheckGPS();
	if (lasttipgroup$ != "NoTips") {
		SetHelpTip(point_tool.TrackGPS);
		}
	}
#--------------------------------------------------------------
#
#	The Record editing dialog
#
class DBEDITOR_SingleRecordWidget Editor;
class XmForm EditMainForm;
string currentTable$ = "";
string team$ = IniReadString("datalogger", "team");
numeric recordNum;
proc EditRecordClose() {
	if (currentTable$ != "") {
		DialogClose(EditMainForm);
		MasterLayer.ActiveElem = 0;
		if (recordNum > 0){
			ViewDrawPinmapElement(view, MasterLayer, recordNum);
			recordNum = 0;
			}
		editRecNum = 0;
		currentTable$ = "";
		}
	SetHelpTip(point_tool.TrackGPS);
	}
proc cbEditRecordOK() {
	local numeric rec;
	rec = DBEditorSingleRecordWidgetSaveChanges(Editor);
	if (rec > 0) {
		# Note, need to get then from the Editor directly. 
		pt.y = DBEditorSingleRecordWidgetGetFieldNum(Editor, "Northing");
		pt.x = DBEditorSingleRecordWidgetGetFieldNum(Editor, "Easting");
		layerIDNum = DBEditorSingleRecordWidgetGetFieldNum(Editor, "ID");
		team$ = DBEditorSingleRecordWidgetGetFieldStr(Editor, "Team");
		IniWriteString("datalogger", "team", team$);
		if(editRecNum == 0) {
			TableWriteRecord(MasterDBTInfo, 0, layerIDNum, pt.y, pt.x, currentTable$);
			}
		else	{
			TableWriteRecord(MasterDBTInfo, layerIDNum, layerIDNum, pt.y, pt.x, currentTable$);
			}
		}
	EditRecordClose();
	}
proc cbEditRecordDelete() {
	if (PopupYesNo("Are you sure you want to delete this record?", 0)) {
		tinfo = DatabaseGetTableInfo(MasterDBase, currentTable$);
		RecordDelete(tinfo, editRecNum);
		RecordDelete(MasterDBTInfo, recordNum);
		EditRecordClose();
		}
	}
proc cbEditRecordCancel() {
	EditRecordClose();
	}
#-----------------------------------------------------------------------
#
#	This opens the form
#
proc EditRecord(table$) {
	local class PUSHBUTTONITEM okitem, cancelitem, deleteitem;
	local class XmForm buttonrow;
	local class XmSeparator sep;
	pt = ViewTransPointViewToLayer(view, MasterLayer, point_tool.point);
	SetHelpTip(-1);	# Shut them off while editing.  Too destracting
	layerIDNum = MasterDBTInfo.NumRecords + 1;
	if (editRecNum > 0)	{
		MasterLayer.NoDrawActiveElem = 1;
		MasterLayer.ActiveElem = recordNum;
		ViewRedraw(view);
		}
	tinfo = DatabaseGetTableInfo(MasterDBase, table$);
	EditMainForm = CreateFormDialog(tinfo.Description); 
	okitem = CreatePushButtonItem("OK", cbEditRecordOK);
	cancelitem = CreatePushButtonItem("Cancel", cbEditRecordCancel);
	if (editRecNum > 0)	{
		deleteitem = CreatePushButtonItem("Delete", cbEditRecordDelete);
		buttonrow = CreateButtonRow(EditMainForm, okitem, deleteitem, cancelitem);
		}
	else {
		buttonrow = CreateButtonRow(EditMainForm, okitem, cancelitem);
		}
	buttonrow.LeftWidget = EditMainForm;
	buttonrow.RightWidget = EditMainForm;
	buttonrow.BottomWidget = EditMainForm;
	sep = CreateHorizontalSeparator(EditMainForm);
	sep.LeftWidget = EditMainForm;
	sep.RightWidget = EditMainForm;
	sep.BottomWidget = buttonrow;
	Editor = DBEditorSingleRecordWidgetCreate(MasterLayer.LayerManager.DBEditor, 
		table$, EditMainForm);
	Editor.OKButton = okitem.widget;
	DBEditorSingleRecordWidgetSetRecord(Editor, editRecNum);
	DBEditorSingleRecordWidgetSetField(Editor, "Northing", pt.y);
	DBEditorSingleRecordWidgetSetField(Editor, "Easting", pt.x);
	if (!editRecNum) {
		DBEditorSingleRecordWidgetSetField(Editor, "Date", Date());
		DBEditorSingleRecordWidgetSetField(Editor, "ID", layerIDNum);
		DBEditorSingleRecordWidgetSetField(Editor, "Team", team$);
		}
	Editor.TopWidget = EditMainForm;
	Editor.LeftWidget = EditMainForm;
	Editor.RightWidget = EditMainForm;
	Editor.BottomWidget = sep;
	currentTable$ = table$;
	DialogOpen(EditMainForm);
	}
################################################################
#
#	This is the callback function which will be called
#	when the exit button is pressed.  
#
proc cbQuit(class widget widget) {
	GPSClose(gpsport);
	DialogClose(form);
	}
################################################################
#
#	This is the callback function which will be called
#	when the dialog goes away.  This can happen either because
#	we called DialogClose() from our Quit callback or because
#	the user closed the dialog using the [X] icon on the title bar.
#
proc cbPopdown(class widget widget) {
	EditRecordClose();
	ViewDestroy(view);
	LayoutDestroy(layout);
	DestroyWidget(form);
	Exit();		# Nothing else from here on!
	}
#------------------------------------------------------------------
# Used to open the button bar should the user close it
#
proc cbOpenBarform(){
	DialogOpen(barform);
	DialogToTop(barform);
	}
#------------------------------------------------------------------
#
#	Callback for the database buttonbar.  Tables are selected based 
#	on the button's LabelString member 
#
proc cbOpenDatabase(class XmPushButton button)	{
	EditRecordClose();	# In case one was open before
	local string dbstring$ = left$(button.LabelString, 3);
	if(dbstring$ == "Pip")	EditRecord("PO");
	if(dbstring$ == "Exp")	EditRecord("EP");
	if(dbstring$ == "Cha")	EditRecord("CH");
	if(dbstring$ == "Fis")	EditRecord("FB");
	if(dbstring$ == "Ero")	EditRecord("ES");
	if(dbstring$ == "Ina")	EditRecord("IB");
	if(dbstring$ == "Unu")	EditRecord("UC");
	if(dbstring$ == "Tra")	EditRecord("TD");
	if(dbstring$ == "In ")	EditRecord("IC");
	if(dbstring$ == "Roa")	EditRecord("RC");
	if(dbstring$ == "Rep")	EditRecord("RE");
	}
proc CB_GPSSourceManager() {
	GPSSourceManagerOpen();
	}
proc UseGPS() {
	if (GPSNumSources() > 0)	{
		ToolSetGPS(point_tool, gpsport);
		point_tool.TrackGPS = 1;
		}
	SetHelpTip(point_tool.TrackGPS);		# Set the help tip for tracking GPS
	}
#------------------------------------------------------------------
#
#	Called when user right-clicks on a symbol. Finds which record
#	it is and pops up the editor for that record
proc FindClosest() {
	local numeric dist;
	local string layerStr$;
	EditRecordClose();	# In case one was open before
	pt = ViewTransPointViewToLayer(view, MasterLayer, point_tool.point);
	recordNum = PinmapLayerFindClosest(MasterLayer, pt, 50, dist);
	if (recordNum == 0) {
		# Nowhere near a point
		UseGPS();
		}
	else	{
		layerIDNum = TableReadFieldNum(MasterDBTInfo, "ID", recordNum);
		layerStr$ = TableReadFieldStr(MasterDBTInfo, "Table", recordNum);
		tinfo = DatabaseGetTableInfo(MasterDBase, layerStr$);
		editRecNum = TableKeyFieldLookup(tinfo, "ID", layerIDNum);
		EditRecord(layerStr$);
		}
	}
#------------------------------------------------------------------
#	Called when the point tool is moved.  If a table is open, update
#	the northing/easting fields to the new location
proc UpdatePosition() {
	if (currentTable$ != "") {
		pt = ViewTransPointViewToLayer(view, MasterLayer, point_tool.point);
		DBEditorSingleRecordWidgetSetField(Editor, "Northing", pt.y);
		DBEditorSingleRecordWidgetSetField(Editor, "Easting", pt.x);
		}
	SetHelpTip(point_tool.TrackGPS);
	}
#------------------------------------------------------------------
#	Called when the user deactivates the HyperIndex tool
#
proc StartPinmap() {
	group = layout.FirstGroup;
#XXX	layout.DlgObjMgrOpen();
	DialogToTop(form);
	pt = ViewTransPointViewToLayer(view, group.FirstLayer, view.Center);
	MasterLayer = GroupQuickAddDBPinmap(group, datafile$, "Tables", "Master", "Easting", "Northing");
#	MasterLayer.Projection = PinMapProj;
	MasterLayer.Region.CoordRefSys = PinMapCRS;
	MasterLayer.IgnoreExtents = 1;
	MasterLayer.PointStyle.xsize = 5;
	MasterLayer.PointStyle.ysize = 5;
	MasterLayer.PointStyle.MapScale = 10000;
	MasterLayer.StyleObject = OpenStyleObject(datafile$, "Stars");
	MasterLayer.StyleByScript = 1;
	MasterLayer.Script = 'Symbol$ = "start1"
					 if (Master.Table == "PO") DrawColor$ = "green"
					 else if (Master.Table == "EP") DrawColor$ = "red"
					 else if (Master.Table == "CH") DrawColor$ = "yellow"
					 else if (Master.Table == "FB") DrawColor$ = "orange"
					 else if (Master.Table == "ES") DrawColor$ = "turquoise3"
					 else if (Master.Table == "IB") DrawColor$ = "blue"
					 else if (Master.Table == "UC") DrawColor$ = "pink"
					 else if (Master.Table == "TD") DrawColor$ = "skyblue"
					 else if (Master.Table == "IC") DrawColor$ = "MidnightBlue"
					 else if (Master.Table == "RC") DrawColor$ = "white"
					 else if (Master.Table == "RE") DrawColor$ = "tan3"
					 DrawSymbol = 1';
	MasterDBase = PinmapLayerOpenDatabase(MasterLayer, "w");
	MasterDBTInfo = DatabaseGetTableInfo(MasterDBase, "Master");
	# These get wiped out by help tips, so way do we bother? 
	MasterLayer.DataTip.Field = PinmapLayerGetFieldInfo(MasterLayer, "Master", "Table");
	MasterLayer.DataTip.Shown = 1;
	MasterLayer.DataTipSearchDist = 100;
	MasterLayer.ShowDataTips = 1;
	GroupSetActiveLayer(group, MasterLayer);
	showfeaturesicon.widget.Sensitive = 1;
	DialogOpen(barform);
	DialogToTop(barform);
	ViewRedrawIfNeeded(view);
	}
proc EndPinmap()	{
   inPointTool = 0;
	showfeaturesicon.widget.Sensitive = 0;
	DialogClose(barform);
	MasterLayer = LayerDestroy(MasterLayer);
	point_tool.TrackGPS = 0;
	SetHelpTip(-1);
	}
proc CB_PointManaged() {
   inPointTool = 1;
	StartPinmap();
#	point_tool.TransParm = ViewGetTransMapToView( view, PinMapProj );
	point_tool.TransParm = ViewGetTransMapToView( view, PinMapCRS );
	if (!point_tool.HasPosition) {		# Give it a default position
		point_tool.point = view.Center;	# Center of the view
		}
	UseGPS();
	}
################################################################
################################################################
#
#	MAIN PROGRAM
#
form = CreateFormDialog("Data Logger");			#create the main form
WidgetAddCallback(form.Shell.PopdownCallback, cbPopdown);
layout = LayoutCreate();
numeric needhyper = 1;
class OBJECTINFO obj;
raster Rast;
if (layoutfile$ != "") {
	LayoutRead(layout, layoutfile$, layoutname$);
	group = layout.FirstGroup;
	}
else {
	obj = SelectInputObject("RASTER,LAYOUT", "Select raster or display layout");
	if (obj.Type == "RASTER") {
   	OpenRasterObject(Rast, obj);
		group = DispCreate2DGroup("group1", layout);
		layer = GroupQuickAddRasterVar(group, Rast);
		if (SubObjectNumber(obj.Filename, obj.Number, "*", "HYPER") <= 0) {
			needhyper = 0;
			}
		}
	else {
		LayoutRead(layout, obj.Filename, obj.Name);
		group = layout.FirstGroup;
		}
	}
view = LayoutCreateView(layout, form, "Data Logger", 640, 480);
#XXXlayout.DlgObjMgrCreate(form);
#XXXlayout.DlgObjMgrOpen();
view.form.TopWidget = form;
view.form.LeftWidget = form;
view.form.RightWidget = form;
view.form.BottomWidget = form;
view.AddGroupIcon.hidden = 1;
view.ZoomToGroupIcon.hidden = 1;
view.ZoomToLayerIcon.hidden = 1;
view.PreviousZoomIcon.hidden = 1;
view.ShowDataTips = 1;	# 0=none, 1=active layer only, 2=all layers
view.ScalePosVisible = 1;
#view.PositionProjection = LatLonProj;
view.PositionProjection = LatLonCRS;
#-----------------------------------------------------------------------
#
#  Buttons for database table icon bar
#
func class PushButtonItem MakeIcon(name$, color$, iconname$) {
	class PUSHBUTTONITEM item;
	item = CreatePushButtonItem(name$, cbOpenDatabase);
	icon_color.Name = color$;
	item.IconClass = "advisor";
	item.IconName = iconname$;
	item.BackgroundColor = icon_color;
	return(item);
	}
barform = CreateFormDialog("Stream Features", view.IconBar);
class XmRowColumn rc;
rc = CreateIconButtonRow(barform, 
	 MakeIcon("Pipe Outfall", 						   "green", 		 "op"),
	 MakeIcon("Exposed or Leaking Pipe", 		   "red", 		 	 "lp"),
	 MakeIcon("Channelization", 					   "yellow", 		 "cs"),
	 MakeIcon("Fish Barrier", 						   "orange", 		 "fb"),
	 MakeIcon("Erosion Site", 						   "turquoise3", 	 "es"),
	 MakeIcon("Inadequate Buffer", 				   "blue",         "ib"),
	 MakeIcon("Unusual Condition", 				   "pink",         "uc"),
	 MakeIcon("Trash Dumping", 					   "skyblue",      "td"),
	 MakeIcon("In or Near Stream Construction",  "MidnightBlue", "ic"),
	 MakeIcon("Road or Railroad Crossing", 	   "white", 		 "rc"),
	 MakeIcon("Representative Site", 				"tan3", 		    "rs")
	 );
if (_context.DisplayInfo.Width < 600) {	# If small screen, make this 2 rows
	rc.NumColumns = 2;	# Is actually number of rows for horizontal XmRowColumn
	rc.Packing = "PACK_COLUMN";
	rc.Orientation = "Horizontal";
	}
ViewAddStandardTools(view);
ViewCreateZoomBoxTool(view);
ViewCreateSlideViewTool(view);
class MDISPTOOL hyper_tool;
if (needhyper) {
	if (IniReadString("SML_ToolBar", "WinPosHyperNavigator") == "") {
		# If no default position for navigator window, give it one or it
		# will default to obscuring the center of the view.
		IniWriteString("SML_ToolBar", "WinPosHyperNavigator", "0 200");
		}
	hyper_tool = ViewCreateHyperIndexTool(view);
	}
point_tool = ViewCreatePointTool(view, "point", "point_select", "standard");  
ToolAddCallback(point_tool.ActivateCallback, FindClosest);
ToolAddCallback(point_tool.PositionSetCallback, UpdatePosition);
ToolAddCallback(point_tool.ManagedCallback, CB_PointManaged);
ToolAddCallback(point_tool.UnManagedCallback, EndPinmap);
ViewAddToolIcons(view);
if (hyper_tool) {
	ViewActivateTool(view, hyper_tool);
	}
else {
	ViewActivateTool(view, point_tool);
	}
#---------------------------------------------------------------
#	create buttons on main "window" toolbar
#
class XmForm br = CreateForm(view.IconBar.parent);
br.TopWidget = br.Parent;
br.TopOffset = 2;
br.RightOffset = 4;
showfeaturesicon = CreatePushButtonItem("Show Stream Features window", cbOpenBarform);
showfeaturesicon.IconClass = "RVCobjects";
showfeaturesicon.IconName = "db_table";
class PUSHBUTTONITEM gpsicon = CreatePushButtonItem("This button returns your tool to the GPS location", UseGPS);
gpsicon.IconClass = "display16";
gpsicon.IconName = "gps_point";
class PUSHBUTTONITEM gpsicon2 = CreatePushButtonItem("GPS Source Manager", CB_GPSSourceManager);
gpsicon2.IconClass = "display16";
gpsicon2.IconName = "gps_controls";
CreateIconButtonRow(br, gpsicon, gpsicon2, showfeaturesicon);
showfeaturesicon.widget.Sensitive = 0;
view.IconBar.RightWidget = br;
#-----------------------------------------------------
#	This is sneeky.  To create the exit button on the 
#	right end of the view's icon bar, create it as a
#	child of the icon bar's parent.  Then change the
#	attachments to wedge it in where we want it.
#
class XmPushButton exitbutton = CreatePushButton(view.IconBar.parent, "Exit");
br.RightWidget = exitbutton;
exitbutton.RightWidget = exitbutton.parent;
exitbutton.TopWidget = exitbutton.parent;
exitbutton.TopOffset = 2;
WidgetAddCallback(exitbutton.ActivateCallback, cbQuit);
#-----------------------------------------------------
#	Open the dialog.
DialogOpen(form);
DialogToTop(form);
if (_context.DisplayInfo.Width < 600) {	# Portrate mode on pen computer
	DialogFullScreen(form);
	}
ViewRedrawIfNeeded(view);
#-----------------------------------------------------
#	Setup the datatips.  This is faster if done after
#	the layer manager is open, becuase that opens
#	the database.
#point_tool.TransParm = ViewGetTransMapToView( view, PinMapProj );
point_tool.TransParm = ViewGetTransMapToView( view, PinMapCRS );
gpsport = GPSOpen(1);	# Open it and add the callback even if no GPS devices.
GPSAddCallback(gpsport.PollCallback, CB_GPSPoll);
if (GPSNumSources() > 0)	{
	ToolSetGPS(point_tool, gpsport);
	point_tool.TrackGPS = 1;
	}
else	{
	PopupMessage(
'No GPS device detected.  Click the GPS
Source Manager icon to configure one.
[middle icon upper right]');
	}
func class ToolTip MakeTip(delay) {
	class ToolTip tip;
	tip = CreateToolTip(view.DrawingArea, "Help filled in later");
	tip.Disabled = 1;
	tip.Delay = delay;
	return(tip);
	}
helptip0 = MakeTip(2000);
helptip1 = MakeTip(helptip0.Delay + 16000);
helptip2 = MakeTip(helptip1.Delay + 16000);
helptip3 = MakeTip(helptip2.Delay + 16000);
helptip4 = MakeTip(helptip3.Delay + 16000);
helptip5 = MakeTip(helptip4.Delay + 16000);
helptip6 = MakeTip(helptip5.Delay + 16000);
helptip7 = MakeTip(helptip6.Delay + 16000);
defaultTipColor = helptip1.BackgroundColor;
if (!hyper_tool) StartPinmap();
#
#	Rather than having the script wait for the dialog
#	to close, setup an OnExit callback.  If the script
#	is exited for any reason (including clicking the
#	exit icon on the tool bar), this function will be
#	called before we're terminated.
#	Then just call WaitForExit().  This will put the
#	script into a suspended state such that it's only
#	waiting for callbacks (including the OnExit one)
#	The only way out of this state is to call Exit()
#
OnExit(cbQuit);	#Call this when the script exits
WaitForExit();		# Will never return