NEsearchCtrl.sml

  Download

More scripts: Interactive

Syntax Highlighing:

comments, key words, predefined symbols, class members & methods, functions & classes
            
## NEsearchCtrl.sml
## Display Control Script that creates Find Area of Interest / Download Orthoimages
## dialog and controls its associated actions for the Nebraska Landviewer Atlas.
## Author: Randy Smith, MicroImages, Inc.
## Original version 20 June 2006
## Revised version 9 April 2008, restructured to work in 2008:74 of the TNT products
## when tiled multithreaded rendering is implemented.
## Requires version 2007:73 of the TNT products.
########################################
### Global variable declarations
########################################
# group/layer/object global variables
class GRE_VIEW myView;		# global class instance for the layout's view window
class GRE_VECTOR_POLYS targetPolys;	# class instance for polygons in layer being searched (used for highlighting)
class GRE_LAYER_VECTOR trLayer;		# township/range vector layer
class GRE_LAYER_VECTOR trsLayer;		# section vector layer
class GRE_LAYER_VECTOR nrdLayer;		# natural resource district vector layer
class GRE_LAYER_VECTOR cntyLayer;	# county vector layer
class GRE_LAYER_VECTOR quadLayer;	# quadrangle vector layer
class GRE_LAYER_VECTOR cityLayer;	# city vector layer
class VECTOR trVector;					# township/range vector object
class VECTOR trsVector;					# section vector object
class VECTOR nrdVector;					# natural resourc district vector object
class VECTOR cntyVector;				# county vector object
class VECTOR quadVector;				# quadrangle vector object
class VECTOR cityVector;				# city/town vector object
class TRANS2D_MAPGEN pTransparm;			## coordinate transformation parameters from screen to vector layer
# global variables for dialog specification and window
class XMLDOC dlgdoc, listdlgdoc;			# class instances for XML documents with dialog specifications
class XMLNODE dlgnode, listdlgnode;		# class instance for node in the XML document corresponding
													# to the dialog
class GUI_DLG dlgwin;						# class instance for the GUI dialog
numeric errXML;								# error value to check ingest of dialog specification
numeric dlgOpened;							# flag to indicate when Find Area dialog has been opened
class GUI_FORMDATA settings;  # structure to hold values retrieved from main search dialog
## handles for dialog controls, needed to clear/reset values on close
class GUI_LAYOUT_BOOK panels;
class GUI_LAYOUT_PAGE resPage;
class GUI_CTRL_TOGGLEBUTTON trToggle, sectToggle, nrdToggle;
class GUI_CTRL_TOGGLEBUTTON cntyToggle, cityToggle, quadToggle;
class GUI_CTRL_EDIT_NUMBER tnumEdit, rnumEdit, secnumEdit;
class GUI_CTRL_COMBOBOX rdirBox, nrdBox;
class GUI_CTRL_EDIT_STRING nameText, statusText, searchText;
class GUI_CTRL_LABEL textfldlabel;
class GUI_CTRL_LISTBOX resList, qqNameListbox;
class GUI_CTRL_PUSHBUTTON searchbutton, viewPolygonBtn, downloadBtn, getOrthoListBtn;
class GUI_LAYOUT_PAGE resPage;
class GUI_FORM_RADIOGROUP crsRGP;
class GUI_CTRL_LABEL zoneLabel;
numeric searchmode;		# flag indicating type of polygon search
								# 1 = township & range, 2 = township/range/section
								# 3 = Natural Resource District name, 4 = county name
								# 5 = 7.5-minute quadrangle name, 6 = city/town name
numeric prevSearchmode;		# records previous search mode when different search is performed; used to
									# enable unhighlighting of element found in previous search
numeric found = 0;				# state variable to indicate if a was polygon found and is currently highlighted in view
numeric matchPolyList[1];	# array to hold element numbers of polygons that match query
numeric townshipList[1];	# array to hold preliminary list of records matching township number
										# in township/range or township/range/section search
numeric matchRecList[1];		# array to hold record numbers of records that match search; use to
										# get element numbers of polygons records are attached to.
numeric zoomChanged;			# 1 if zoom has changed since last redraw, otherwise 0
class STRINGLIST qqList;	### stringlist to hold quarter-quad suffixes for orthoimage download
string fdir$;					### string with one-degree subdirectory name for orthoimage download
string crs$ = "NAD83 / SPCS83 Nebraska zone";		### string with name of Coordinate Reference System for orthoimages
string crsDir$ = "coqspn";	### string with subdirectory name for Nebraska State Plane (default) or UTM orthoimage CRS
string utmZone$ = "14N";		### string with UTM zone number for Coordinate Reference System name.
numeric crsCode = 1;				### internal code for the four possible CRS settings, to be passed to
										### the MicroImages redirect script to construct download page.
numeric qqCount;				### number of quarter-quad orthoimages available for selected quadrangle
class STRINGLIST qqFileNameStrList;	### stringlist to hold quarter-quad names for current quadrangle
class STRINGLIST qqFileRootSL;  		### stringlist to hold filename root for current quarter-quad, used to
												### construct download page
class FILEPATH tempFile;		### filepath instance for name of temporary file for download html page
string language$;
numeric quadHighlighted;	### flag to indicate if quadrangle polygon is currently highlighted
numeric previouslyDrawn = 0;		### flag to indicate if the Layout has been previously drawn.
###################################################################
# procedure to open the Find Area dialog window.  If already open,
# will expose dialog (bring to foreground).
proc openDlg()
	{
	dlgwin.Open();
	}
###################################################################
# procedure called when loading of the layout object is complete
proc OnLayoutLoadEnd (
   class GRE_LAYOUT layout
   ) {
		# locate the Nebraska Data group in the layout
		local class GRE_GROUP Group;
		Group = layout.FirstGroup;
		while (Group.Name != "Nebraska Data")
			Group = Group.NextGroup;
		### get the vector layer handles by name from the group
		trLayer = Group.GetLayerByName("Townships");
		trsLayer = Group.GetLayerByName("Sections");
		nrdLayer = Group.GetLayerByName("NRDs");
		cntyLayer = Group.GetLayerByName("Counties");
		quadLayer = Group.GetLayerByName("USGS Quads");
		cityLayer = Group.GetLayerByName("Cities");
		### get the vector object from each vector layer to be used in the search
		DispGetVectorFromLayer(trVector, trLayer);
		DispGetVectorFromLayer(trsVector, trsLayer);
		DispGetVectorFromLayer(nrdVector, nrdLayer);
		DispGetVectorFromLayer(cntyVector, cntyLayer);
		DispGetVectorFromLayer(quadVector, quadLayer);
		DispGetVectorFromLayer(cityVector, cityLayer);
		searchmode = 1;		# set default search mode to township & range
		prevSearchmode = 0;
		language$ = _context.Locale;
		###############################################
		#### specification in XML for main query dialog
		###############################################
		local string xml$ = '<?xml version="1.0"?>
		<root>
			<strings language="enu">	<!-- Englinsh -->
			</strings>
			<strings language="esn">	<!-- Spanish -->
				<string id="Find Area of Interest / Download Orthoimages">Encuentre Area de Interés / Descargue Ortoimágenes</string>
				<string id="Find Area">Encuentre Area</string>
				<string id=" Find by Township + Range +/- Section "> Busque por Township + Range +/- Section </string>
				<string id=" Find by Name "> Encuentre por Nombre </string>
				<string id="Natural Resource District">Distrito de Recursos Naturales</string>
				<string id="County">Condado</string>
				<string id="City or Town">Ciudad o Pueblo</string>
				<string id="Name:">Nombre:</string>
				<string id=" Find "> Busque </string>
				<string id="Results">Resultados</string>
				<string id="You searched for:">Usted buscó por:</string>
				<string id="  View Selected Area  ">  Vea Area Seleccionada  </string>
				<string id="Orthoimages">Ortoimágenes</string>
				<string id="Zoom to map scale factor of 250000 or less to enable selection."> Zoom a escala de mapa 1:250000 o menos para habilitar selección. </string>
				<string id=" Get Orthoimage List "> Liste Ortoimágenes </string>
				<string id="for quadrangle in center of view.">para cuadrángulo en centro de la vista.</string>
				<string id="JPEG-compressed color orthoimages for this quadrangle:">Ortoimágenes color JPEG comprimidas para este cuadrángulo:</string>
				<string id="(select one or more images for download):">(seleccione una o más imágenes para descargar)</string>
				<string id="Select Coordinate Reference System:">Seleccione Sistema de Coordenadas de Referencia:</string>
				<string id="Go to Download Page">Vaya a Página de Descarga</string>
				<string id="Search Status:">Estatus de la Búsqueda:</string>
				<string id=" Help "> Ayuda </string>
			</strings>
			<strings language="trk">	<!-- Turkish-->
				<string id="Find Area of Interest / Download Orthoimages">Alan Bul / Ortho Görüntü İndir</string>
				<string id="Find Area">Alan Bul</string>
				<string id=" Find by Township + Range +/- Section "> Township + Range +/- Section ile Bul </string>
				<string id=" Find by Name "> İsim ile Bul </string>
				<string id="Natural Resource District">Doál Kaynak Bölgesi</string>
				<string id="City or Town">İl veya İlçe</string>
				<string id="Name:">İsim:</string>
				<string id=" Find "> Bul </string>
				<string id="Results">Sonuçlar</string>
				<string id="You searched for:">Aradıń±nız:</string>
				<string id="  View Selected Area  ">  Seçili Alanı Görüntüle  </string>
				<string id="Orthoimages">Ortho Görüntüler</string>
				<string id="Zoom to map scale factor of 250000 or less to enable selection.">Seçmek için 250000 veya daha küçük bir ölçeå gidin.</string>
				<string id=" Get Orthoimage List "> Ortho İmajları Listele </string>
				<string id="for quadrangle in center of view.">görüntü merkezindeki quadrangle için.</string>
				<string id="JPEG-compressed color orthoimages for this quadrangle:"> Bu quadrangle için JPEG renkli ortho görünüler:</string>
				<string id="(select one or more images for download):">(indirmek için tek yada daha fazla görüntü seçin):</string>
				<string id="Select Coordinate Reference System:">Koordinat Referans Sistemi Seçiniz:</string>
				<string id="Go to Download Page">İndirme Sayfasına Git</string>
				<string id="Search Status:">Arama Durumu:</string>
				<string id=" Help "> Yardım </string>
			</strings>
			<dialog id= "nesearch" Title="Find Area of Interest / Download Orthoimages" ResourceLookup="true" Buttons="" HorizResize="Expand" VertResize="Fixed" OnOpen="OnOpenDialog()">
				<book id="panels">
					<page Name="Find Area" OnSetActive="onFindPageActive()">
						<groupbox Name=" Find by Township + Range +/- Section " ExtraBorder="8">
							<pane Orientation="horizontal" HorizResize="Fixed" VertResize="Fixed">
								<togglebutton id="tr" Name="Township" Selected="true" OnChanged="OnTRactive()"/>
								<editnumber id="tnum" Width="2" MaxLength="2" Precision="0" MinVal="1" MaxVal="35" Default="10"/>
								<space Width="8"/>
									<label>Range</label>
								<editnumber id="rnum" Width="2" MaxLength="2" Precision="0" MinVal="1" MaxVal="58" Default="06"/>
								<combobox id="rdir" Default="E" VertResize="Expand" OnSelection="OnChngDir()">
									<item Name="E" Value="E"/>
									<item Name="W" Value="W"/>
								</combobox>
								<space Width="20"/>
								<togglebutton id="sect" Name="Section" HorizAlign="Right" OnChanged="OnSectActive()"/>
								<editnumber id="secnum" Width="2" MaxLength="2" Precision="0" MinVal="1" MaxVal="36" Default="26" HorizAlign="Right" Enabled="no"/>
							</pane>
						</groupbox>
						<groupbox Name=" Find by Name " ExtraBorder="8">
							<pane Orientation="horizontal">
								<togglebutton id="nrd" Name="Natural Resource District" OnChanged="OnNRDactive()"/>
							</pane>
							<pane Orientation="horizontal" HorizAlign="Left">
								<space Width="30"/>
								<combobox id="nrdlist" Enabled="no"/>
							</pane>
							<pane Orientation="horizontal" HorizAlign="Left">
								<togglebutton id="cnty" Name="County" OnChanged="OnCntyActive()"/>
								<togglebutton id="quad" Name="7.5-minute Quad" HorizAlign="Left" OnChanged="OnQuadActive()"/>
								<togglebutton id="city" Name="City or Town" HorizAlign="Right" OnChanged="OnCityActive()"/>
							</pane>
							<pane Orientation="horizontal" HorizAlign="Center" HorizResize="Fixed">
								<label id="textfldlabel" Enabled="false">Name:</label>
								<edittext id="nametext" Width="25" MaxLength="25" Enabled="false" OnActivate="OnSearch()"/>
							</pane>
						</groupbox>
						<pane HorizAlign="Center">
							<pushbutton id="searchbutton" Name=" Find " HorizAlign="Center" HorizResize="Expand" VertResize="Fixed" OnPressed="OnSearch()"/>
						</pane>
					</page>
					<page id="resPage" Name="Results" VertAlign="Top" HorizResize="Fixed" VertResize="Fixed" OnSetActive="onResPageActive()">
						<pane Orientation="vertical" HorizResize="Fixed">
							<pane Orientation="horizontal" VertAlign="Top" VertResize="Fixed">
								<label HorizResize="Fixed">You searched for:</label>
								<edittext id="searchText" ReadOnly="true" Width="30" HorizAlign="Left"/>
							</pane>
							<listbox id="resList" SelectStyle="single" Width="35" Height="11" VertResize = "Expand" HorizResize="Expand" OnChangeSelection="onListSelect()" OnDoubleClick="onViewPoly()"/>
							<pushbutton id="viewPolygon" Name="  View Selected Area  " VertResize="Fixed" Enabled="no" OnPressed="onViewPoly()"/>
						</pane>
					</page>
					<page Name="Orthoimages" VertAlign="Top" VertResize="Fixed" HorizResize="Fixed" OnSetActive="onOrthoPageActive()">
						<label HorizResize="Expand">Zoom to map scale factor of 250000 or less to enable selection.</label>
						<pane Orientation="horizontal">
							<pushbutton id="getOrthoListBtn" Name=" Get Orthoimage List " OnPressed="onGetOrthoList()" HorizResize="Fixed" VertRize="Fixed" Enabled="false"/>
							<label>for quadrangle in center of view.</label>
						</pane>
						<groupbox ExtraBorder="4">
							<label>JPEG-compressed color orthoimages for this quadrangle:</label>
							<label>(select one or more images for download):</label>
							<listbox id="qqNameListbox" Height="4" SelectStyle="multi" VertResize="Fixed"/>
							<label>Select Coordinate Reference System:</label>
							<pane Orientation="horizontal" VertResize="Fixed" HorizResize="Fixed">
								<radiogroup id="crsRGP" Default="spcs" Orientation="horizontal" VertAlign="Top"  OnSelection="onDOQcrs()">
									<item Name="NAD83 / SPCS83 Nebraska zone" Value="spcs"/>
									<item Name="NAD83 / UTM zone" Value="utm"/>
								</radiogroup>
								<label id="zoneLabel" VertAlign="Top" HorizAlign="Left">14N</label>
							</pane>
						</groupbox>
						<pushbutton id="downloadBtn" Name="Go to Download Page" Enabled="false" OnPressed="onDownloadBtnPressRedirect()"/>
					</page>
				</book>
				<pane Orientation="horizontal">
					<label HorizResize="Fixed">Search Status:</label>
					<edittext id="statusText" ReadOnly="true" Width="30" HorizAlign="Left"/>
				</pane>
				<pane Orientation="horizontal" HorizAlign="Right">
					<label HorizResize="Expand"> </label>
					<pushbutton id="helpbutton" Name=" Help " HorizResize="Fixed" WidthGroup="1" OnPressed="OnHelp()"/>
				</pane>
			</dialog>
		</root>';
		### parse XML text for main search dialog into memory;
		### return an error code (number < 0) if there are syntax errors
		errXML = dlgdoc.Parse(xml$);
		if (errXML < 0)
			{
			PopupError(errXML);
			Exit();
			}
		### get the dialog element from the parsed XML document and
		### show error message if the dialog element can't be found
		dlgnode = dlgdoc.GetElementByID("nesearch");
		if (dlgnode == 0)
			{
			PopupMessage("Could not find dialog node in XML document");
			Exit();
			}
		### get the dialog element from the parsed XML document and
		### show error message if the dialog element can't be found
		dlgnode = dlgdoc.GetElementByID("nesearch");
		if (dlgnode == 0)
			{
			PopupMessage("Could not find dialog node in XML document");
			Exit();
			}
		### Set the XML dialog element as the source for the GUI_DLG
		### class instance we are using for the dialog window.
		dlgwin.SetXMLNode(dlgnode);
		### Create the modeless dialog
		dlgwin.CreateModeless();
		### get handles for dialog controls using their ID's in the dialog specification
		panels = dlgwin.GetPaneByID("panels");
		resPage = dlgwin.GetPaneByID("resPage");
		trToggle = dlgwin.GetCtrlByID("tr");
		sectToggle = dlgwin.GetCtrlByID("sect");
		nrdToggle = dlgwin.GetCtrlByID("nrd");
		nrdBox = dlgwin.GetCtrlByID("nrdlist");
		cntyToggle = dlgwin.GetCtrlByID("cnty");
		cityToggle = dlgwin.GetCtrlByID("city");
		quadToggle = dlgwin.GetCtrlByID("quad");
		tnumEdit = dlgwin.GetCtrlByID("tnum");
		rnumEdit = dlgwin.GetCtrlByID("rnum");
		secnumEdit = dlgwin.GetCtrlByID("secnum");
		rdirBox = dlgwin.GetCtrlByID("rdir");
		nameText = dlgwin.GetCtrlByID("nametext");
		textfldlabel = dlgwin.GetCtrlByID("textfldlabel");
		statusText = dlgwin.GetCtrlByID("statusText");
		searchText = dlgwin.GetCtrlByID("searchText");
		resList = dlgwin.GetCtrlByID("resList");
		searchbutton = dlgwin.GetCtrlByID("searchbutton");
		viewPolygonBtn = dlgwin.GetCtrlByID("viewPolygon");
		qqNameListbox = dlgwin.GetCtrlByID("qqNameListbox");
		crsRGP = dlgwin.GetCtrlByID("crsRGP");
		downloadBtn = dlgwin.GetCtrlByID("downloadBtn");
		zoneLabel = dlgwin.GetCtrlByID("zoneLabel");
		getOrthoListBtn = dlgwin.GetCtrlByID("getOrthoListBtn");
		#################################################################################
		### populate combobox list for NRD names from the NRD vector's database table
		# loop through the NRD polygons (there is one record per polygon) and add
		# the NRD name to the combobox list and set polygon number (converted to string)
		# as ID for that entry.
		nrdBox.SetSorted(1);			# tells combobox to sort list as items are added
		local numeric i;
		for i = 1 to nrdVector.$Info.NumPolys
			{
			nrdBox.AddItem( nrdVector.Poly[i].NRDinfo.NRD_LOWER$, NumToStr(i) );
			}
		nrdBox.SetSelectedItemID("19");	# sets first item in sorted list as default
													# (brute force approach: by knowing its polygon number)
		### set up stringlist with DOQQ quadrant identifiers
		qqList.AddToEnd("NE");
		qqList.AddToEnd("NW");
		qqList.AddToEnd("SW");
		qqList.AddToEnd("SE");
		panels.SetActivePage(0);	### set Settings panel to be active (on top)
		resPage.SetEnabled(0);
   }	# end of OnLayoutLoadEnd
###################################################################
# procedure called when the view is created for this layout
proc OnViewDrawEnd (
   class GRE_VIEW view
   ) {
	if (previouslyDrawn == 0)
		{
		# set flag to indicate that layout has been drawn before and dialog opened.
		previouslyDrawn = 1;
		# add Icon Pushbutton to View's toolbar to open/Expose Find Area dialog
		# determine whether TNT version is before or after 7.4 to determine which method to use.
		# Code between $ifdef and $endif commands are only parsed for the relevant versions,
		# preventing syntax check failures
		class GUI_CTRL_PUSHBUTTON openDlgBtn;
		openDlgBtn.CreateIcon(view.ToolBarPane, "GEOREF_FIND", "Open Find Area Dialog");
		openDlgBtn.SetOnPressed(openDlg);
		# reassign provided local GRE_VIEW class instance to global instance
		myView = view;
		# Set the ZoomIn tool (created by tool script) as the active tool
		view.ActivateToolName("ZoomIn (Variable by Scale");
		# Open the dialog window
		openDlg();
		}
	else		# on subsequent redraws of the layout view:
		{
		# enable the Get Ortho List button if zoomed in below threshold map scale factor
		if (view.CurrentMapScale <= 250000)
			then getOrthoListBtn.SetEnabled(1);
		else
			getOrthoListBtn.SetEnabled(0);
		}
	}
######################################################################
# procedure called when the tool script dialog window opens
proc OnOpenDialog()
	{
	dlgwin.ForceOnScreen();		### forces the dialog window to appear on-screen if its default
	}									### position would leave it partially off-screen.
###################################################################
# procedure called when township/range toggle button is activated;
# sets search mode and appropriate state of other controls.
proc OnTRactive ()
	{
	if ( trToggle.GetValue() )
		{
		searchmode = 1;
		sectToggle.SetEnabled(1);
		tnumEdit.SetEnabled(1);
		rnumEdit.SetEnabled(1);
		rdirBox.SetEnabled(1);
		nrdToggle.SetValue(0, 0);
		nrdBox.SetEnabled(0);
		cntyToggle.SetValue(0, 0);
		cityToggle.SetValue(0, 0);
		quadToggle.SetValue(0, 0);
		textfldlabel.SetEnabled(0);
		nameText.ClearValue(0);
		nameText.SetEnabled(0);
		statusText.ClearValue(0);
		}
	else									# if toggle is off after press, turn it back on
		trToggle.SetValue(1, 0);	# (only turned off by turning on another toggle)
	}	# end of OnTRactive()
####################################################################
# procedure called when range direction combobox selection changes;
# used to set appropriate maximum for the range number field.
proc OnChngDir ()
	{
	if ( rdirBox.GetSelectedItemID() == "E" )
		{
		rnumEdit.SetRange(1, 19, 0);		# set maximum range number to 19 for E
		}
	else rnumEdit.SetRange(1, 58, 0);	# set maximum range number to 58 for W
	}
#############################################################
# procedure called when section toggle button is activated;
# sets search mode and appropriate state of other controls.
proc OnSectActive ()
	{
	if ( sectToggle.GetValue() )
		{
		searchmode = 2;
		secnumEdit.SetEnabled(1);
		trToggle.SetEnabled(0);
		statusText.ClearValue(0);
		}
	else
		{
		searchmode = 1;
		secnumEdit.SetEnabled(0);
		trToggle.SetEnabled(1);
		statusText.ClearValue(0);
		}
	} # end of OnSectActive()
############################################################
# procedure called when NRD toggle button is activated;
# sets search mode and appropriate state of other controls.
proc OnNRDactive ()
	{
	if ( nrdToggle.GetValue() ) 	# if toggle is on after press
		{
		searchmode = 3;
		nrdBox.SetEnabled(1);
		sectToggle.SetValue(0, 0);
		sectToggle.SetEnabled(0);
		secnumEdit.SetEnabled(0);
		trToggle.SetEnabled(1);
		trToggle.SetValue(0, 0);
		tnumEdit.SetEnabled(0);
		rnumEdit.SetEnabled(0);
		rdirBox.SetEnabled(0);
		cntyToggle.SetValue(0, 0);
		cityToggle.SetValue(0, 0);
		quadToggle.SetValue(0, 0);
		textfldlabel.SetEnabled(0);
		nameText.ClearValue(0);
		nameText.SetEnabled(0);
		statusText.ClearValue(0);
		}
	else									# if toggle is off after press, turn it back on
		nrdToggle.SetValue(1, 0);	# (only turned off by turning on another toggle)
	} # end of OnNRDactive()
#############################################################
# procedure called when County toggle button is activated;
# sets search mode and appropriate state of other controls.
proc OnCntyActive ()
	{
	if ( cntyToggle.GetValue() )
		{
		searchmode = 4;
		sectToggle.SetValue(0, 0);
		sectToggle.SetEnabled(0);
		secnumEdit.SetEnabled(0);
		trToggle.SetEnabled(1);
		trToggle.SetValue(0, 0);
		tnumEdit.SetEnabled(0);
		rnumEdit.SetEnabled(0);
		rdirBox.SetEnabled(0);
		nrdToggle.SetValue(0, 0);
		nrdBox.SetEnabled(0);
		cityToggle.SetValue(0, 0);
		quadToggle.SetValue(0, 0);
		textfldlabel.SetEnabled(1);
		nameText.ClearValue(0);
		nameText.SetEnabled(1);
		nameText.SetFocus();
		statusText.ClearValue(0);
		}
	else									# if toggle is off after press, turn it back on
		cntyToggle.SetValue(1, 0);	# (only turned off by turning on another toggle)
	} # end of OnCntyActive()
###############################################################
# procedure called when Quadrangle toggle button is activated;
# sets search mode and appropriate state of other controls.
proc OnQuadActive ()
	{
	if ( quadToggle.GetValue() )
		{
		searchmode = 5;
		sectToggle.SetValue(0, 0);
		sectToggle.SetEnabled(0);
		secnumEdit.SetEnabled(0);
		trToggle.SetEnabled(1);
		trToggle.SetValue(0, 0);
		tnumEdit.SetEnabled(0);
		rnumEdit.SetEnabled(0);
		rdirBox.SetEnabled(0);
		nrdToggle.SetValue(0, 0);
		nrdBox.SetEnabled(0);
		cntyToggle.SetValue(0, 0);
		cityToggle.SetValue(0, 0);
		textfldlabel.SetEnabled(1);
		nameText.ClearValue(0);
		nameText.SetEnabled(1);
		nameText.SetFocus();
		statusText.ClearValue(0);
		}
	else									# if toggle is off after press, turn it back on
		quadToggle.SetValue(1, 0);	# (only turned off by turning on another toggle)
	} # end of OnQuadActive()
###############################################################
# procedure called when City/Town toggle button is activated;
# sets search mode and appropriate state of other controls.
proc OnCityActive ()
	{
	if ( cityToggle.GetValue() )
		{
		searchmode = 6;
		sectToggle.SetValue(0, 0);
		sectToggle.SetEnabled(0);
		secnumEdit.SetEnabled(0);
		trToggle.SetEnabled(1);
		trToggle.SetValue(0, 0);
		tnumEdit.SetEnabled(0);
		rnumEdit.SetEnabled(0);
		rdirBox.SetEnabled(0);
		nrdToggle.SetValue(0, 0);
		nrdBox.SetEnabled(0);
		cntyToggle.SetValue(0, 0);
		quadToggle.SetValue(0, 0);
		textfldlabel.SetEnabled(1);
		nameText.ClearValue(0);
		nameText.SetEnabled(1);
		nameText.SetFocus();
		statusText.ClearValue(0);
		}
	else									# if toggle is off after press, turn it back on
		cityToggle.SetValue(1, 0);	# (only turned off by turning on another toggle)
	} # end of OnCityActive()
################################################################
# procedure called when the Help button on dialog is pressed
proc OnHelp () {
	local string file$ = _context.ScriptDir + "/" + "NEatlasHelp.pdf";
	RunAssociatedApplication(file$);
}
##############################################################
### procedure to pan and zoom to the selected polygon
proc doZoom (polyNum)
	{
	local numeric vwScale;
	local string zoom$;
	local class GRE_LAYER_VECTOR hVectLayer;
	local class VECTOR hVector;
	# get local vector layer and vector variables from the vector layer
	# used by the current search type
	if (searchmode == 1)
		{
		hVectLayer = trLayer;
		DispGetVectorFromLayer(hVector, trLayer);
		}
	else if (searchmode == 2)
		{
		hVectLayer = trsLayer;
		DispGetVectorFromLayer(hVector, trsLayer);
		}
	else if (searchmode == 3)
		{
		hVectLayer = nrdLayer;
		DispGetVectorFromLayer(hVector, nrdLayer);
		}
	else if (searchmode == 4)
		{
		hVectLayer = cntyLayer;
		DispGetVectorFromLayer(hVector, cntyLayer);
		}
	else if (searchmode == 5)
		{
		hVectLayer = quadLayer;
		DispGetVectorFromLayer(hVector, quadLayer);
		}
	else if (searchmode == 6)
		{
		hVectLayer = cityLayer;
		DispGetVectorFromLayer(hVector, cityLayer);
		}
	# highlight selected polygon
	hVectLayer.NoFillWhenHighlight;
	targetPolys.HighlightSingle(polyNum, "Replace", 0);
	###########################################################
	### get information needed to check if highlighted polygon
	### is already in the view, in which case don't need to pan
	###########################################################
	### get extents of highlighted polygon from Internal database table as min and max points
	local CLASS POINT2D minPt, maxPt;
	minPt.x = hVector.poly[polyNum].Internal.MinX;
	minPt.y = hVector.poly[polyNum].Internal.MinY;
	maxPt.x = hVector.poly[polyNum].Internal.MaxX;
	maxPt.y = hVector.poly[polyNum].Internal.MaxY;
	### set up RECT from polygon extents
	local class RECT polyExtents;			# extents of polygon in screen coordinates
	polyExtents.pt1 = minPt;
	polyExtents.pt2 = maxPt;
	### get extents of View in screen coordinates
	### upper left corner of view pane = 0,0, so lower right coordinates = width, height
	local CLASS POINT2D UpLeft, LowRight;
	LowRight.x = myView.Width;
	LowRight.y = myView.Height;
	### set up RECT from view extents in screen coordinates
	local class RECT viewExtents;			# extents of view in screen coordinates
	viewExtents.pt1 = UpLeft;
	viewExtents.pt2 = LowRight;
	#################################################################################
	### get TRANSPARM from screen coordinates to target vector layer coordinates for
	### current view position and convert extents RECT to layer coordinates
	#################################################################################
	pTransparm = myView.GetTransLayerToScreen(hVectLayer, 1);
	viewExtents = pTransparm.ConvertRectFwd(viewExtents);
	# if highlighted polygon is already in view and its extents are > 50% of view extents,
	# don't need to pan/zoom to it.
	if (viewExtents.ContainsRect(polyExtents) && polyExtents.GetArea() > 0.5 * viewExtents.GetArea() )
		{
		myView.SetMessage("");
#		myView.StatusBarClear();
		}
	else
		{
		hVectLayer.ZoomToActiveElement();	# pan and zoom to extents of highlighted polygon
		targetPolys.HighlightSingle(polyNum);
		}
	} # end of doZoom()
##################################################################################
# procedure called to check if there was a previous successful search of different
# type and if so to unhighlight elements in previous vector layer
proc checkPreviousSearch ()
	{
	if (prevSearchmode > 0)		# if not the first search, go on with check
		{
		if ( searchmode <> prevSearchmode) 	# if not same search as previous
			{
			if (found == 1)	# if a polygon is currently found and highlighted, continue
				{
				if (prevSearchmode == 1) then
					trLayer.UnhighlightAllElements();
				else if (prevSearchmode == 2) then
					trsLayer.UnhighlightAllElements();
				else if (prevSearchmode == 3) then
					nrdLayer.UnhighlightAllElements();
				else if (prevSearchmode == 4) then
					cntyLayer.UnhighlightAllElements();
				else if (prevSearchmode == 5) then
					quadLayer.UnhighlightAllElements();
				else if (prevSearchmode == 6) then
					cityLayer.UnhighlightAllElements();
				}
			}
		}
	} # end of checkPreviousSearch()
################################################################
# procedure called when no polygon matches the current search
proc onFoundNone ()
	{
	myView.SetMessage("");			### clear View window message and status bar (no redraw will occur
#	myView.StatusBarClear();		### to do this automatically)
	if (resList.GetCount() > 0) then		# clear previous results list if present
		resList.DeleteAllItems();
	### call use-defined procedure to check previous search type and
	### unhighlight elements in previous vector layer if needed
	checkPreviousSearch();
	### update Search Result field in dialog
	local string type$, status$;
	if (language$ == "enu")
		{
		if (searchmode == 1) then
			status$ = "No township matches these criteria.";
		else if (searchmode == 2) then
			status$ = "No section matches these criteria.";
		else if (searchmode == 4) then
			status$ = "No county matches this name.";
		else if (searchmode == 5) then
			status$ = "No quadrangle matches this name.";
		else if (searchmode == 6) then
			status$ = "No city or town matches this name.";
		}
	else if (language$ == "esn")
		{
		if (searchmode == 1) then
			status$ = "No hay township similar a estos criterios.";
		else if (searchmode == 2) then
			status$ = "No hay section similar a estos criterios.";
		else if (searchmode == 4) then
			status$ = "No hay condado similar a este nombre.";
		else if (searchmode == 5) then
			status$ = "No hay quadrangle similar a este nombre.";
		else if (searchmode == 6) then
			status$ = "No hay ciudad o pueblo similar a este nombre.";
		}
	else if (language$ == "trk")
		{
		if (searchmode == 1) then
			status$ = "Bu kriterlere uygun township bulunamadı.";
		else if (searchmode == 2) then
			status$ = "Bu kriterlere uygun section bulunamadı.";
		else if (searchmode == 4) then
			status$ = "Bu kriterlere uygun county bulunamadı.";
		else if (searchmode == 5) then
			status$ = "Bu kriterlere uygun quadrangle bulunamadı.";
		else if (searchmode == 6) then
			status$ = "Bu kriterlere uygun il veya ilçe bulunamadı.";
		}
	found = 0;
	statusText.SetValue(status$, 0);
	}	# end of OnFoundNone()
#####################################################################
# procedure called when one polygon matches search criterion
proc onFoundOne (polyNum)
	{
	myView.SetMessage("");
#	myView.StatusBarClear();
	### call use-defined procedure to check previous search type and
	### unhighlight elements in previous vector layer if needed
	checkPreviousSearch();
	### update Search Result field in dialog
	local string type$, name$, prefix$, status$, t$, r$, dir$, s$;
	if (language$ == "enu") then
		prefix$ = "Found one:";
	else if (language$ == "esn") then
		prefix$ = "Se encontró una";
	else if (language$ == "trk") then
		prefix$ = "Bir adet bulunan:";
	if (searchmode == 1)
		{
		type$ = "township";
		t$ = trVector.Poly[polyNum].TRStable.TWNSHP$;
		r$ = trVector.Poly[polyNum].TRStable.RNG$;
		dir$ = trVector.Poly[polyNum].TRStable.DIR$;
		name$ = sprintf("T %u, R %u %s", t$, r$, dir$);
		}
	else if (searchmode == 2)
		{
		type$ = "section";
		t$ = trsVector.Poly[polyNum].Sections.TWNSHP$;
		r$ = trsVector.Poly[polyNum].Sections.RNG$;
		dir$ = trsVector.Poly[polyNum].Sections.DIR$;
		s$ = trsVector.Poly[polyNum].Sections.SECTION$;
		name$ = sprintf("T %u, R %u %s, sec %u", t$, r$, dir$, s$);
		}
	else if (searchmode == 3)
		{
		if (language$ == "enu") then
			type$ = "NRD";
		else if (language$ == "esn") then
			type$ = "DRN";
		else if (language$ == "trk") then
			type$ = "DKB";
		name$ = nrdVector.Poly[polyNum].NRDinfo.NRD_LOWER$;
		}
	else if (searchmode == 4)
		{
		if (language$ == "enu" or language$ == "trk") then
			type$ = "county";
		else if (language$ == "esn") then
			type$ = "condado";
		name$ = cntyVector.Poly[polyNum].County.CTYNAME_UP$;
		}
	else if (searchmode == 5)
		{
		type$ = "quadrangle";
		name$ = quadVector.Poly[polyNum].quad_numb.QUAD_NAME$;
		}
	else
		{
		if (language$ == "enu") then
			type$ = "city or town";
		else if (language$ == "esn") then
			type$ = "ciudad o pueblo";
		else if (language$ == "trk") then
			type$ = "İl veya İlçe";
		name$ = cityVector.Poly[polyNum].City.CITY_NAME$;
		}
	status$ = sprintf("%s %s: %s", prefix$, type$, name$);
	statusText.SetValue(status$, 0);
	prevSearchmode = searchmode;	# reset previous search mode to current
	found = 1;
	doZoom(polyNum);
	}	# end of onFoundOne()
###########################################################################
# procedure called when more than one polygon matches search criterion
proc onFoundMultiple (polyCount)
	{
	### call use-defined procedure to check previous search type and
	### unhighlight elements in previous vector layer if needed
	checkPreviousSearch();
	if (language$ == "enu") then
		statusText.SetValue( sprintf("%d polygons found.", polyCount), 0);
	else if (language$ == "esn") then
		statusText.SetValue( sprintf("%d polígonos encontrados.", polyCount), 0);
	else if (language$ == "trk") then
		statusText.SetValue( sprintf("%d poligon bulundu.", polyCount), 0);
	local string listItem$, searchPrefix$;
	local numeric j, polyNum;
	if (searchmode == 4)		# search for counties
		{
		if (language$ == "enu" or language$ == "trk") then
			searchText.SetValue( sprintf("County: %s", settings.GetValueStr("nametext") ), 0);
		else if (language$ == "esn") then
			searchText.SetValue( sprintf("Condado: %s", settings.GetValueStr("nametext") ), 0);
		for j = 1 to polyCount		# loop through found county polygons and get name
			{
			polyNum = matchPolyList[j];
			listItem$ =  cntyVector.Poly[polyNum].County.CTYNAME_UP$;
			resList.AddItem(listItem$);
			}
		}
	else if (searchmode == 5)		# search for map quadrangles
		{
		searchText.SetValue( sprintf("Quadrangle: %s", settings.GetValueStr("nametext") ), 0);
		for j = 1 to polyCount
			{
			polyNum = matchPolyList[j];
			listItem$ =  quadVector.Poly[polyNum].quad_numb.QUAD_NAME$;
			resList.AddItem(listItem$);
			}
		}
	else if (searchmode == 6)
		{
		if (language$ == "enu") then
			searchText.SetValue( sprintf("City/town: %s", settings.GetValueStr("nametext") ), 0);
		else if (language$ == "esn") then
			searchText.SetValue( sprintf("Ciudad/pueblo: %s", settings.GetValueStr("nametext") ), 0);
		else if (language$ == "trk") then
			searchText.SetValue( sprintf("İl veya İlçe: %s", settings.GetValueStr("nametext") ), 0);
		for j = 1 to polyCount
			{
			polyNum = matchPolyList[j];
			listItem$ =  cityVector.Poly[polyNum].City.CITY_NAME$;
			resList.AddItem(listItem$);
			}
		}
	resPage.SetEnabled(1);
	panels.SetActivePage(1);
	}	# end of onFoundMultiple()
##########################################################
# procedure called when item in result list is selected
proc onListSelect ()
	{
	viewPolygonBtn.SetEnabled(1);
	}
###############################################################
# procedure called when View Selected Area button is pressed or
# result list selection is double-clicked
proc onViewPoly ()
	{
	local numeric polyNum;		# element number of polygon to highlight
	polyNum = matchPolyList[ resList.GetSelectedItemIndex() + 1 ];
	onFoundOne(polyNum);
	} # end of OnViewPoly()
###############################################################
# Procedure called when search for county, quadrangle, or city/town
# is run with no name entered.  Used to check current language
# to show status message in that language
proc onSearchWithNoName ()
	{
	if (language$ == "enu") then
		statusText.SetValue("Please enter a name for search.", 0);
	else if (language$ == "esn") then
		statusText.SetValue("Por favor entre un nombre para la búsqueda.", 0);
	else if (language$ == "trk") then
		statusText.SetValue("Lütfen arama için bir isim girin.", 0);
	found = 0;
	}
###############################################################
## procedure called when Find button on dialog is pressed
###############################################################
proc OnSearch ()
	{
	settings = dlgwin.GetValues();	# get control settings (values from dialog and store in GUI_FORMDATA
	local numeric n = 0;
	local numeric polyCount = 0;
	local numeric numRecords = 0;
	local numeric i = 0;
	local numeric recNum = 0;
	local string test$;
	local numeric numTokens, j;
	ResizeArrayClear(matchPolyList, 0);
	ResizeArrayClear(matchRecList, 0);
	if (resList.GetCount() > 0)
		{ 									# clear previous results list if present
		resList.DeleteAllItems();
		searchText.ClearValue(0);
		resPage.SetEnabled(0);
		}
	###################################################
	# search by township and range number/direction
	###################################################
	if (searchmode == 1)
		{
		# get values for township, range, and direction from dialog as strings
		local string township$, range$, rangedir$;
		township$ = NumToStr( settings.GetValueNum("tnum") );
			if ( strlen(township$) == 1 ) then township$ = "0" + township$;
		range$ = NumToStr( settings.GetValueNum("rnum") );
			if ( strlen(range$) == 1 ) then range$ = "0" + range$;
		rangedir$ = settings.GetValueStr("rdir");
		targetPolys = trLayer.Poly;
		####################################################################################
		### Narrow down the township/range search by using a fast search on township number
		### using a function that takes advantage of an index on the selected field to speed the search.
		### Returns a list of record numbers to an array. (After final search will need to find the
		### element numbers of the polygons the matching records are attached to.)
		######################################################################################
		numRecords = TableKeyFieldLookupList(trVector.Poly.TRStable, "TWNSHP", township$, townshipList, "Equals");
		######################################################################
		### search through the returned set of records for those that match
		### the requested range number and put in array of matching records.
		######################################################################
		for i = 1 to numRecords
			{
#			myView.SetStatusBar(i, numRecords);		### update View window's status bar
			recNum = townshipList[i];
			## find records matching township number and range number
			if ( (trVector.Poly.TRStable[@recNum].TWNSHP$ == township$) &&
					(trVector.Poly.TRStable[@recNum].RNG$ == range$) )
				{
				## check range direction
				if (trVector.Poly.TRStable[@recNum].DIR$ == rangedir$)
					{
					polyCount ++;												# increment counter
					ResizeArrayPreserve(matchRecList, polyCount);	# resize records array to accommodate new value
					matchRecList[polyCount] = recNum;					# add record number to array
					}
				}
			}
		if (polyCount == 0) then				### no polygons found
			onFoundNone();
		else								### one or more polygons found
			{
			TableGetRecordListElementList(trVector.Poly.TRStable, matchRecList, polyCount, matchPolyList);
			if (polyCount == 1) then
				onFoundOne( matchPolyList[1] );
			else
				onFoundMultiple(polyCount);
			}
		}
	##################################################################
	# search by township and range number/direction and section number
	##################################################################
	else if (searchmode == 2)
		{
		# get values for township, range, direction and section from dialog settings as strings
		local string township$, range$, rangedir$, section$;
		township$ = NumToStr( settings.GetValueNum("tnum") );
			if ( strlen(township$) == 1 ) then township$ = "0" + township$;
		range$ = NumToStr( settings.GetValueNum("rnum") );
			if ( strlen(range$) == 1 ) then range$ = "0" + range$;
		rangedir$ = settings.GetValueStr("rdir");
		section$ = NumToStr( settings.GetValueNum("secnum") );
			if ( strlen(section$) == 1 ) then section$ = "0" + section$;
		targetPolys = trsLayer.Poly;
		###########################################################################################
		### Narrow down the township/range/section search by using a fast search on township number
		### using a function that takes advantage of an index on the selected field to speed the search.
		### Returns a list of record numbers to an array. (After final search will need to find the
		### element numbers of the polygons the matching records are attached to.)
		###########################################################################################
		numRecords = TableKeyFieldLookupList(trsVector.Poly.Sections, "TWNSHP", township$, townshipList, "Equals");
		################################################################################
		### search through the returned set of records for those that match
		### the requested range number and section and put in array of matching records.
		################################################################################
		for i = 1 to numRecords
			{
#			myView.SetStatusBar(i, numRecords);		### update View window's status bar
			recNum = townshipList[i];
			## find records matching township number and range number
			if ( (trsVector.Poly.Sections[@recNum].TWNSHP$ == township$) &&
					(trsVector.Poly.Sections[@recNum].RNG$ == range$) )
				{
				## check range direction
				if (trsVector.Poly.Sections[@recNum].DIR$ == rangedir$)
					{
					## find section in selected township
					if (trsVector.Poly.Sections[@recNum].SECTION$ == section$)
						{
						polyCount ++;												# increment counter
						ResizeArrayPreserve(matchRecList, polyCount);	# resize records array to accommodate new value
						matchRecList[polyCount] = recNum;					# add record number to array
						}
					}
				}
			}
		if (polyCount == 0) then				### no polygons found
			onFoundNone();
		else								### one or more polygons found
			{
			TableGetRecordListElementList(trsVector.Poly.Sections, matchRecList, polyCount, matchPolyList);
			if (polyCount == 1) then
				onFoundOne( matchPolyList[1] );
			else
				onFoundMultiple(polyCount);
			}
		}
	#####################################
	# search by Natural Resource District
	#####################################
	else if (searchmode == 3) {
		# get the NRD selection from dialog settings
		local string id$ = settings.GetValueStr("nrdlist");
		targetPolys = nrdLayer.Poly;
		polyCount = 1;
		ResizeArrayPreserve(matchPolyList, polyCount);
		matchPolyList[polyCount] = StrToNum(id$);
		if (polyCount == 0) then
			onFoundNone();
		else if (polyCount == 1) then
			onFoundOne( matchPolyList[1] );
		else
			onFoundMultiple(polyCount);
		}
	##################################
	# search by County name
	##################################
	else if (searchmode == 4) {
		# get county name from dialog settings
		local string cntyName$ = toupper$( settings.GetValueStr("nametext") );
		local numeric cntyNameLen = strlen(cntyName$);
		if (cntyName$ == "") then
			onSearchWithNoName();
		else
			{
			targetPolys = cntyLayer.Poly;
			# loop through county polygons to check if any parts of name begin with search text;
			# element numbers of matching polygons are stored in array matchPolyList
			for n = 1 to cntyVector.$Info.NumPolys
				{
				test$ = cntyVector.Poly[n].County.COUNTY_NAME$;
				# first check for exact match of name to search string
				if (cntyName$ == test$)
					{
					polyCount ++;
					ResizeArrayPreserve(matchPolyList, polyCount);
					matchPolyList[polyCount] = n;
					}
				else		# check if name contains search string
					{
					numTokens = NumberTokens(test$, " ");
					for j = 1 to numTokens
						{
						if ( left$( GetToken(test$, " ", j), cntyNameLen) == cntyName$)
							{
							polyCount ++;
							ResizeArrayPreserve(matchPolyList, polyCount);
							matchPolyList[polyCount] = n;
							}
						}
					}
				}
			if (polyCount == 0) then
				onFoundNone();
			else if (polyCount == 1) then
				onFoundOne( matchPolyList[1] );
			else
				onFoundMultiple(polyCount);
			}
		}
	######################################
	# search by 7.5-minute quadrangle name
	######################################
	else if (searchmode == 5) {
		# get quadrangle name from dialog settings
		local string quadName$ = toupper$( settings.GetValueStr("nametext") );
		local numeric quadNameLen = strlen(quadName$);
		if (quadName$ == "") then
			onSearchWithNoName();
		else
			{
			targetPolys = quadLayer.Poly;
			# loop through quadrangle polygons to check if any parts of name begin with search text;
			# element numbers of matching polygons are stored in array matchPolyList
			for n = 1 to quadVector.$Info.NumPolys
				{
				test$ = quadVector.Poly[n].quad_numb.QUADNAME$;
				# first check for exact match of name to search string
				if (quadName$ == test$)
					{
					polyCount ++;
					ResizeArrayPreserve(matchPolyList, polyCount);
					matchPolyList[polyCount] = n;
					}
				else		# check if name contains search string
					{
					numTokens = NumberTokens(test$, " ");
					for j = 1 to numTokens
						{
						if ( left$( GetToken(test$, " ", j), quadNameLen) == quadName$)
							{
							polyCount ++;
							ResizeArrayPreserve(matchPolyList, polyCount);
							matchPolyList[polyCount] = n;
							}
						}
					}
				}
			if (polyCount == 0) then
				onFoundNone();
			else	if (polyCount == 1) then
				onFoundOne( matchPolyList[1] );
			else
				onFoundMultiple(polyCount);
			}
		}
	################################
	# search by city/town name
	################################
	else {	# searchmode == 6
		# get city/town name from dialog settings
		local string cityName$ = toupper$( settings.GetValueStr("nametext") );
		local numeric cityNameLen = strlen(cityName$);
		if (cityName$ == "") then
			onSearchWithNoName();
		else
			{
			targetPolys = cityLayer.Poly;
			# loop through city polygons to check if name contains search text;
			# element numbers of matching polygons are stored in array matchPolyList
			for n = 1 to cityVector.$Info.NumPolys
				{
				test$ = toupper$(cityVector.Poly[n].City.CITY_NAME$);
				# first check for exact match of name to search string
				if (cityName$ == test$)
					{
					polyCount ++;
					ResizeArrayPreserve(matchPolyList, polyCount);
					matchPolyList[polyCount] = n;
					}
				else		# check if name contains search string
					{
					numTokens = NumberTokens(test$, " ");
					for j = 1 to numTokens
						{
						if ( left$( GetToken(test$, " ", j), cityNameLen) == cityName$)
							{
							polyCount ++;
							ResizeArrayPreserve(matchPolyList, polyCount);
							matchPolyList[polyCount] = n;
							}
						}
					}
				}
			if (polyCount == 0) then
				onFoundNone();
			else if (polyCount == 1) then
				onFoundOne( matchPolyList[1] );
			else
				onFoundMultiple(polyCount);
			}
		}
	prevSearchmode = searchmode;
	} # end of OnSearch()
#######################################################################
### Procedure called when Find Area tabbed panel is activated.
proc onFindPageActive()
	{
	if (previouslyDrawn == 1)
		{
		quadLayer.SetVisibleInView(1, 0);
		myView.RedrawIfNeeded();
		if (quadHighlighted == 1)
			{
			quadLayer.UnhighlightAllElements(1);
			quadHighlighted = 0;
			}
		}
	}
#######################################################################
### Procedure called when Results tabbed panel is activated.
proc onResPageActive()
	{
	quadLayer.SetVisibleInView(1, 0);
	myView.RedrawIfNeeded();
	if (quadHighlighted == 1)
		{
		quadLayer.UnhighlightAllElements(1);
		quadHighlighted = 0;
		}
	}
#######################################################################
### Procedure called when Orthoimage tabbed panel is activated.
proc onOrthoPageActive()
	{
	# if map scale < 250,000, turn on quadrangle layer and enable button to
	# get list of available quarter-quad images for the quad in center of view
	if (myView.CurrentMapScale <= 250000)
		{
		quadLayer.SetVisibleInView(1, 1);
		myView.RedrawIfNeeded();
		getOrthoListBtn.SetEnabled(1);
		}
	else
		getOrthoListBtn.SetEnabled(0);
	}
#######################################################################
### procedure called when Get Orthoimage List button is pressed
proc onGetOrthoList()
	{
	local class POINT2D center;		### coordinates of center of view
	local class TRANSPARM qTransparm;	### coordinate transformation parameters
	local numeric quadNum;				### element number of quadrangle polygon under cursor at left-click
	local string quadID$;				### Nebraska DNR FSA quad id number from database
	local string quadName$;				### name of 7.5-minute quadrangle
	local string qqNameList$, qqFileRoot$;
	local numeric k;
	local CLASS STRINGLIST availqqStrList;		### stringlist to hold quadrant identifiers for current quad
	### check listboxes on DOQQs panel and clear them if necessary
	if (qqNameListbox.GetCount() > 0) then
		qqNameListbox.DeleteAllItems();
	### get screen coordinates of center of view and store as point
	center.x = myView.Width / 2;
	center.y = myView.Height / 2;
	### get TRANSPARM from screen coordinates to quadrangle vector layer (object) coordinates
	### for current view position and transform point to layer coordinates
	qTransparm = myView.GetTransLayerToScreen(quadLayer, 1);
	center = qTransparm.ConvertPoint2DFwd(center);
#	PopupMessage( sprintf("center x = %.1f, y = %.1f", center.x, center.y) );
	### find the quadrangle enclosing the center point and highlight it in the view
	quadNum = FindClosestPoly(quadVector, center.x, center.y, GetLastUsedGeorefObject(quadVector) );
	if (quadNum > 0)
		{
		quadLayer.Poly.HighlightSingle(quadNum);
		qqFileNameStrList.Clear();
		qqFileRootSL.Clear();
		### get quadrangle identifier and name from database
		quadID$ = quadVector.Poly[quadNum].quad_numb.DNR_Q_ID$;
		quadName$ = quadVector.Poly[quadNum].quad_numb.QUAD_NAME$;
		### get count of available orthoimages for quadrangle from database
		qqCount = quadVector.Poly[quadNum].quadsQQ.NUM_QQs;
		if (qqCount == 0)
			{
			if (language$ == "enu") then
				statusText.SetValue("No orthoimages available for quadrangle.", 0);
			else if (language$ == "esn") then
				statusText.SetValue("No hay ortoimágenes disponibles por quadrangle.", 0);
			else if (language$ == "trk") then
				statusText.SetValue("Quadrangle için Ortho Görüntü bulunamadı.", 0);
			downloadBtn.SetEnabled(0);			# disable Download button
			}
		else
			{
			downloadBtn.SetEnabled(1);			# enable Download button
			if (qqCount < 4)	# quad has less than three orthoimages available
				{
				availqqStrList.Clear();		# clear stringlist with available quarter-quads
				if (quadVector.Poly[quadNum].quadsQQ.NE) then		## make stringlist with available quarter-quads
					availqqStrList.AddToEnd("NE");
				if (quadVector.Poly[quadNum].quadsQQ.NW) then
					availqqStrList.AddToEnd("NW");
				if (quadVector.Poly[quadNum].quadsQQ.SW) then
					availqqStrList.AddToEnd("SW");
				if (quadVector.Poly[quadNum].quadsQQ.SE) then
					availqqStrList.AddToEnd("SE");
				### loop through available quadrants of quadrangle to fill in lists of quarter quadrangle
				### names on Orthoimages panel of dialog window
				for k = 1 to qqCount
					{
					qqNameList$ = sprintf("%s quadrangle, %s quarter", quadName$, availqqStrList.GetString(k-1) );
					qqNameListbox.AddItem(qqNameList$, qqNameList$);
					qqFileNameStrList.AddToEnd(qqNameList$);
					qqFileRoot$ = quadID$ + tolower$( availqqStrList.GetString(k-1) );
					qqFileRootSL.AddToEnd(qqFileRoot$);
					}
				}
			else if (qqCount == 4)
			{
			### loop through all four quadrants of quadrangle to fill in lists of quarter quadrangle
			### names on Orthoimages panel of dialog window
			for k = 1 to 4
				{
				qqNameList$ = sprintf("%s quadrangle, %s quarter", quadName$, qqList.GetString(k-1) );
				qqNameListbox.AddItem(qqNameList$, qqNameList$);
				qqFileNameStrList.AddToEnd(qqNameList$);
				qqFileRoot$ = quadID$ + tolower$( qqList.GetString(k-1) );
				qqFileRootSL.AddToEnd(qqFileRoot$);
				}
			}
			if (language$ == "enu") then
				statusText.SetValue( sprintf("%d orthoimages found.", qqCount), 0);
			else if (language$ == "esn") then
				statusText.SetValue( sprintf("%d ortoimágenes encontrados.", qqCount), 0);
			else if (language$ == "trk") then
				statusText.SetValue( sprintf("%d ortho görüntüler bulundu.", qqCount), 0);
			### set final directory name for relevant 1-degree block from database
			fdir$ = quadVector.Poly[quadNum].quad_numb.D_BLOCK$;
			### get map coordinates of view center location in NAD83 / Geographic coordinates to
			### determine UTM zone for display in dialog.  (Could also get this from the
			### block number string (last three characters are longitude), but section below
			### provides example of using Coordinate Reference System classes.
			####################################################################################
			local class GEOREF quadGeoref;
			quadGeoref = GetLastUsedGeorefObject(quadVector);		# get georeference info for quadrangle vector
			local class POINT2D mapPt;		# click-position in map coordinates of quadrangle vector
			mapPt = ObjectToMap(quadVector, center.x, center.y, quadGeoref);
			### set up NAD83 / Geographic coordinate reference system for map coordinate transformation;
			### first set up similar predefined CRS, then switch datum
			local class SR_COORDREFSYS crsGeog = "Geographic2D_WGS84_Deg";
			crsGeog.Datum = "NAD83";
			### set up TRANSPARM from quadrangle vector's map coordinates to NAD83 / Geographic coordinates
			local class TRANSPARM crsTRANS;
			crsTRANS.InputCoordRefSys = quadGeoref.CoordRefSys;
			crsTRANS.OutputCoordRefSys = crsGeog;
			### use TRANSPARM to convert map coordinates
			mapPt = crsTRANS.ConvertPoint2DFwd(mapPt);
			### find UTM zone from longitude of mouse-click location and
			### update label for UTM CRS on dialog; also set UTM zone string for
			### constructing full CRS name for download page
			if (mapPt.x > -96)
				{
				zoneLabel.SetLabel("15N");
				utmZone$ = "15N";
				if (crsDir$ == "coqutm") then crsCode = 2;
				}
			else if (mapPt.x > -102)
				{
				zoneLabel.SetLabel("14N");
				utmZone$ = "14N";
				if (crsDir$ == "coqutm") then crsCode = 3;
				}
			else
				{
				zoneLabel.SetLabel("13N");
				utmZone$ = "13N";
				if (crsDir$ == "coqutm") then crsCode = 4;
				}
	quadHighlighted = 1;
	#		panels.SetActivePage(2);	# bring DOQQs panel to top in dialog
			}
		}
	else
		{
		if (language$ == "enu") then
			statusText.SetValue("No quadrangle found.", 0);
		else if (language$ == "esn") then
			statusText.SetValue("No hay quadrangle encontrado.", 0);
		else if (language$ == "trk") then
			statusText.SetValue("Quadrangle bulunamadı.", 0);
		qqFileNameStrList.Clear();					# clear stringlist with filenames
		quadLayer.UnhighlightAllElements(1);
		downloadBtn.SetEnabled(0);					# disable download button
		}
	}
#########################################################################
### procedure called when Coordinate Reference System radiogroup setting
### on DOQQs panel is changed
proc onDOQcrs()
	{
	if (crsRGP.GetSelected() == "utm" )
		{
		crs$ ="NAD83 / UTM zone " + utmZone$;
		crsDir$ = "coqutm";				### set subdirectory for URL
		if (utmZone$ == "15N") then
			crsCode = 2;					### set numeric code to be passed to MI redirect page
		else if (utmZone$ == "14N") then
			crsCode = 3;
		else if (utmZone$ == "13N") then
			crsCode = 4;
		}
	else if (crsRGP.GetSelected() == "spcs" )
		{
		crs$ = "NAD83 / SPCS83 Nebraska zone";
		crsDir$ = "coqspn";				### set subdirectory for URL
		crsCode = 1;						### set numeric code to be passed to MI redirect page
		}
	} # end onDOQcrs()
##################################################################################
### procedure called when Download button is pressed;
### version used to generate local web page with direct links to NE DNR ftp site.
##################################################################################
proc onDownloadBtnPress()
	{
	if (tempFile.Exists() ) then
		DeleteFile(tempFile);
	### get number of quarter-quadrangles selected in listbox
	local numeric selCount = qqNameListbox.GetSelectedItemCount();
	local numeric i;		# counter for looping through selected list items
	local numeric listindex;	# index number (0-based) of current selected list item
	local string imgFileRoot$;	# filename root for image to be downloaded
	### set up strings to construct url for download
	local string urlbase$ = "ftp://dnrftp.dnr.state.ne.us/pub/data/coqarea/coq03/";
	local string url$ = sprintf( "%s%s/%s", urlbase$, crsDir$, fdir$ ); 	## string for full ftp directory path
	## strings with html code for static parts of local download page
	local string htmlStart$, htmlHR$, htmlEnd$;
	htmlStart$ = '<html><head><title>Download Links</title></head>
	<body>
	<p><h2>Download the images you have chosen by right-clicking on the links below.</h2></p>
	<p>Download both files for each image.  The *.jgw file provides georeference
	information for the image.  Also note the Coordinate Reference System shown
	below, which you will need to specify when you import the image. (Print this
	page as a reminder.)</p>
	<hr color="red">\n';
	htmlHR$ = '<hr color="red">\n';
	htmlEnd$ = "</body></html>";
	### create temporary html file and assemble download page for selected images
	tempFile = CreateTempFileName();
	tempFile.SetExtension(".htm");
	local class FILE downloadPage;
	downloadPage = fopen(tempFile, "w");
	# write start of download page to file
	fwritestring(downloadPage, htmlStart$);
	# write coordinate reference system name to download page
	fwritestring(downloadPage, sprintf("<blockquote><h3>%s</h3></blockquote>\n", crs$) );
	fwritestring(downloadPage, htmlHR$);
	if (selCount > 0)		# if items have been selected from quarter-quad list:
		{
		### get info for selected quarter-quadrangle images and write QQ name and links to
		### download page.
		for i = 1 to selCount
			{
			listindex = qqNameListbox.GetSelectedItemIndex(i-1);
			fwritestring(downloadPage, sprintf("<p><h3>%s:</h3></p>\n", qqFileNameStrList.GetString(listindex) ) );	# write name string from stringlist
	#		fwritestring(downloadPage, sprintf("<p><h3>%s:</h3></p>\n", qqNameListbox.GetSelectedItemID(i-1) ) );		# write name string from ID of selected item
			imgFileRoot$ = qqFileRootSL.GetString(listindex);
			fwritestring(downloadPage, sprintf('<p><a href="%s/%s.jgw">%s.jgw</a></p>', url$, imgFileRoot$, imgFileRoot$) );
			fwritestring(downloadPage, sprintf('<p><a href="%s/%s.jpg">%s.jpg</a></p>', url$, imgFileRoot$, imgFileRoot$) );
			}
		fclose(downloadPage);
		}
	else if (selCount == 0)		# no list items selected; make entries for all items in list
		{
		for i = 1 to qqNameListbox.GetCount()
			{
			# need to get names from stringlist; can't use ID's of list items because none are selected
			fwritestring(downloadPage, sprintf("<p><h3>%s:</h3></p>\n", qqFileNameStrList.GetString(i-1) ) );
			imgFileRoot$ = qqFileRootSL.GetString(i-1);
			fwritestring(downloadPage, sprintf('<p><a href="%s/%s.jgw">%s.jgw</a></p>', url$, imgFileRoot$, imgFileRoot$) );
			fwritestring(downloadPage, sprintf('<p><a href="%s/%s.jpg">%s.jpg</a></p>', url$, imgFileRoot$, imgFileRoot$) );
			}
		fclose(downloadPage);
		}
	RunAssociatedApplication(tempFile);
	} # end onDownloadBtnPress()
##################################################################################
### procedure called when Download button is pressed; version used to dynamically
### generate a links page on MicroImages web site instead of a local html page.
### Allows MicroImages to redirect in case NE DNR links change.
proc onDownloadBtnPressRedirect()
	{
	### get number of quarter-quadrangles selected in listbox
	local numeric selCount = qqNameListbox.GetSelectedItemCount();
	local numeric i;		# counter for looping through selected list items
	local numeric listindex;	# index number (0-based) of current selected list item
	local string imgFileRoot$;	# filename root for image to be downloaded
	local string urlbase$ = "https://www.microimages.com/redirect/nednr/index.html?";
	local string url$ = sprintf("%scrsDir=%s&fdir=%s&crs=%d", urlbase$, crsDir$, fdir$, crsCode);
	if (selCount > 0)		# if items have been selected from quarter-quad list:
		{
		### get info for selected quarter-quadrangle images and write parameters to the
		### URL string to be passed to the MI redirect page.
		for i = 1 to selCount
			{
			listindex = qqNameListbox.GetSelectedItemIndex(i-1);
			url$ += sprintf( "&Name%d=%s:", i, qqFileNameStrList.GetString(listindex) );
			url$ += sprintf("&Root%d=%s", i, qqFileRootSL.GetString(listindex));
			}
		}
	else if (selCount == 0)		# no list items selected; make entries for all items in list
		{
		for i = 1 to qqNameListbox.GetCount()
			{
			url$ += sprintf("&Name%d=%s:", i, qqFileNameStrList.GetString(i-1) );
			url$ += sprintf("&Root%d=%s", i, qqFileRootSL.GetString(i-1) );
			}
		}
#	PopupMessage(url$);
	RunAssociatedApplication(url$);
	} # end onDownloadBtnPressRedirect()
######################################################
## function called when a DataTip should be generated
func OnViewDataTipShowText (
   class GRE_VIEW view,
   class POINT2D point,
   class TOOLTIP datatip
   ) {
   numeric retval = 1;		## value returned to have normal DataTip text shown
	datatip.Delay = 3000;
	## set borders for DataTip box
	datatip.MarginHeight = 5;
	datatip.MarginWidth = 5;
   return retval;
   } # end of OnViewDataTipShowText