/******************************

 Program Source: bud32.c -> BWmin.exe
 First Build: August 2018

  
  Using ISourceDLL
  instead of IMGDLL

 This is an experimental, developmental version

 An attempt is being made to hold results in text form in the JPEG bud images

 *******************************/
#define _CRT_SECURE_NO_WARNINGS  // this is for Visual Studio Ultimate

#include "windows.h"
#include   "bud32.h"
#include "BudDefs.h"  // All #define's and globals not in bud32.h

/*****************************************************************/
int PASCAL WinMain
(
HINSTANCE hInstance,		/* current instance         */
HINSTANCE hPrevInstance,	/* previous instance        */
LPSTR lpCmdLine,			/* command line             */
int nCmdShow				/* show-window type (open/icon) */
)
{
    MSG msg;                     /* message              */

    if (!hPrevInstance)          /* Other instances of app running? */
    if (!InitApplication(hInstance)) /* Initialize shared things */
        return (FALSE);      /* Exits if unable to initialize     */

    /* Perform initializations that apply to a specific instance */

    if (!InitInstance(hInstance, nCmdShow))
        return (FALSE);

    /* Acquire and dispatch messages until a WM_QUIT message is received. */

    while (GetMessage(&msg,    /* message structure              */
          NULL,                /* handle of window receiving the message */
    (UINT)NULL,                /* lowest message to examine          */
    (UINT)NULL))               /* highest message to examine         */
	{
    if (
		!TranslateAccelerator(hWndBud,  hAccel,  &msg)
		&&
		!TranslateAccelerator(hWndRslt, hAccel2, &msg)
		&&
		!TranslateAccelerator(hWndCtrl, hAccel4, &msg)
	   )
	{
		     hWndNow = msg.hwnd ;

    TranslateMessage(&msg);    /* Translates virtual key codes       */
    DispatchMessage(&msg);     /* Dispatches message to window       */
    }
	}
    return (msg.wParam);       /* Returns the value from PostQuitMessage */
}

BOOL InitApplication(HINSTANCE hInstance)
{
    WNDCLASS wc;
	
	hOvBrush = CreateSolidBrush(RGB(243,243,187)) ;
	hbkBrush = CreateSolidBrush(GetSysColor(COLOR_WINDOW)) ;
   
	/* Fill in window class structure with parameters that describe the
       window. Items set for any registration carry over and are set for
	   subsequent registrations. */

	/* This is the "Measurement Window" */

    wc.style = CS_OWNDC|CS_NOCLOSE|CS_DBLCLKS|
		       CS_BYTEALIGNCLIENT|
		       CS_BYTEALIGNWINDOW ;     /* Class style(s).                    */
    wc.lpfnWndProc = BudWndProc;        /* Function to retrieve messages for  */
                                        /* windows of this class.             */
    wc.cbClsExtra = 0;                  /* No per-class extra data.           */
    wc.cbWndExtra = 0;                  /* No per-window extra data.          */
    wc.hInstance  = hInstance;          /* Application that owns the class.   */
    wc.hIcon      = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON0));
    wc.hCursor    = NULL ;              /* No class cursor: specified at run time */
    wc.hbrBackground =  GetStockObject(BLACK_BRUSH);
    wc.lpszMenuName  =  NULL ;      /* Name of menu resource in .RC file. */
    wc.lpszClassName = "BudClass";  /* Name used in call to CreateWindow. */

 if (RegisterClass(&wc))
    {
      wc.style         =  CS_OWNDC | CS_NOCLOSE, 
	  wc.lpfnWndProc   =  PrintLayoutProc ;
      wc.lpszClassName = "PrintLayout" ;
      wc.lpszMenuName  =  NULL ;
      wc.hCursor        = NULL ; 
      wc.hbrBackground =  GetStockObject(LTGRAY_BRUSH) ;
    }

    if (RegisterClass(&wc))
    {
	  wc.style         = CS_OWNDC | CS_NOCLOSE |
		                 CS_BYTEALIGNCLIENT |
						 CS_BYTEALIGNWINDOW,
      wc.lpfnWndProc   = ScanWndProc ;
      wc.lpszClassName = "ScanClass" ;
      wc.hbrBackground = GetStockObject(LTGRAY_BRUSH);
	  wc.hCursor = LoadCursor(NULL, IDC_ARROW) ;
    }

    if (RegisterClass(&wc))
    {
      wc.lpfnWndProc   = BannerWndProc ;   // Sign-on banner class
      wc.lpszClassName = "FlagClass" ;
    }

    if (RegisterClass(&wc))	
    {
      wc.style         = CS_SAVEBITS ;	   // tip window class
      wc.lpfnWndProc   = OverlayProc ;
      wc.lpszMenuName  = NULL ;
      wc.lpszClassName = "Overlay" ;
      wc.hbrBackground =  hOvBrush ;
    }

    if (RegisterClass(&wc))	
    {
      wc.style         = CS_OWNDC ;
      wc.lpfnWndProc   = PreviewProc ;		// Preview Window class
      wc.lpszMenuName  = NULL ;
      wc.lpszClassName = "PreviewClass" ;
      wc.hbrBackground =  hbkBrush ;
    }

    if (RegisterClass(&wc))	
    {
      wc.style         = CS_OWNDC ;       // Control Window class
      wc.lpfnWndProc   = CtrlWndProc ;
      wc.lpszMenuName  = "CtrlMenu" ;
      wc.lpszClassName = "CtrlClass" ;
      wc.hbrBackground = GetStockObject(LTGRAY_BRUSH) ;
    }

    if (RegisterClass(&wc)) 
    {
      wc.style         = CS_OWNDC | CS_NOCLOSE ;
      wc.lpfnWndProc   = CollateProc ; // Collation (archiving etc) window class
      wc.lpszMenuName  = "CollateMenu" ;
      wc.lpszClassName = "CollateClass" ;
    }

    if (RegisterClass(&wc))	
    {
      wc.style         = CS_OWNDC | CS_NOCLOSE ;
      wc.lpfnWndProc   = ListingsProc ;			 // Listing window class
      wc.lpszMenuName  = NULL ;
      wc.lpszClassName = "ListingClass" ;
    }

    if (RegisterClass(&wc))
    {
      wc.style         = CS_OWNDC | CS_NOCLOSE |
		                 CS_BYTEALIGNCLIENT |
						 CS_BYTEALIGNWINDOW ;
      wc.lpfnWndProc   = ResultsProc ;			 // Results window class
      wc.lpszMenuName  = NULL ;
      wc.lpszClassName = "ResultClass" ;
      wc.hbrBackground = GetStockObject(BLACK_BRUSH) ;
    }

    if (RegisterClass(&wc))
    {
      wc.style         = CS_OWNDC | CS_NOCLOSE |
		                 CS_BYTEALIGNCLIENT |
						 CS_BYTEALIGNWINDOW ;
      wc.lpfnWndProc   =  ImageryProc ;
      wc.lpszClassName = "AcqClass" ;
      wc.lpszMenuName  = "AcquireMenu" ;
      wc.hbrBackground =  GetStockObject(LTGRAY_BRUSH) ;
    }

    if (RegisterClass(&wc))
    {
      wc.lpfnWndProc   =  GraphProc ;
      wc.lpszClassName = "Graphing" ;
      wc.lpszMenuName  =  NULL ;
    }

    if (RegisterClass(&wc))
    {
      wc.lpfnWndProc   =  ArchiveWorkProc ;
      wc.lpszClassName = "ArchiveOps" ;
      wc.hbrBackground =  GetStockObject(WHITE_BRUSH) ;
    }

    if (RegisterClass(&wc))
    {
      wc.lpfnWndProc   =  RasterProc ;
      wc.lpszClassName = "PGRaster" ;
    }

    if (RegisterClass(&wc))
    {
      wc.lpfnWndProc   =  SelectivityProc ;
      wc.lpszClassName = "SelCurve" ;
      wc.hbrBackground =  GetStockObject(LTGRAY_BRUSH) ;
    }


    if (RegisterClass(&wc))
    {
      wc.lpfnWndProc   =  ViewerProc ;
      wc.lpszClassName = "ViewNodal" ;
      wc.hbrBackground =  GetStockObject(BLACK_BRUSH) ;
    }
    if (RegisterClass(&wc)) return (TRUE ) ;

    return (FALSE) ;
}

/*******************************************************************/
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
	HDC hdc ;
   UINT cbString ;
   char chReplace ;

   char     buff[255] = "\0" ;
   char szMRFile[180] = "\0" ;
   char   buffer[255] = "\0" ;

    int i, j, lpy, wwid, whyt ;
 double u ;

    hInst = hInstance ;

       // Create some Fonts

             lstrcpy(lf.lfFaceName, Face) ;
				  hdc =      CreateDC( "DISPLAY", NULL, NULL, NULL ) ;
				  lpy = GetDeviceCaps( hdc, LOGPIXELSY ) ;
          lf.lfHeight = -MulDiv(8,  lpy, 72) ;
                 hfnt = CreateFontIndirect(&lf) ;
          lf.lfHeight = -MulDiv(7,  lpy, 72) ;
                hfnt1 = CreateFontIndirect(&lf) ;
          lf.lfHeight = -MulDiv(12, lpy, 72) ;
                hfnt2 = CreateFontIndirect(&lf) ;
          lf.lfHeight = -MulDiv(5,  lpy, 72) ;
                hfnt4 = CreateFontIndirect(&lf) ;
    
             lstrcpy(lf.lfFaceName, Greek) ;
          lf.lfHeight = -MulDiv(8,  lpy, 72) ;
                 hgrk = CreateFontIndirect(&lf) ;
          lf.lfHeight = -MulDiv(6,  lpy, 72) ;
                hgrk1 = CreateFontIndirect(&lf) ;
          lf.lfHeight = -MulDiv(12, lpy, 72) ;
                hgrk2 = CreateFontIndirect(&lf) ;
          lf.lfHeight = -MulDiv(5,  lpy, 72) ;
                hgrk4 = CreateFontIndirect(&lf) ;

	 // Get the current screen resolution
			   horpix = GetDeviceCaps(hdc, HORZRES) ;
			   verpix = GetDeviceCaps(hdc, VERTRES) ;

			DeleteDC(hdc) ;

// Some pens for general use
   bluePen = CreatePen( PS_SOLID, 1, RGB(0,0,255)) ;     // blue
  blueWPen = CreatePen( PS_SOLID, 3, RGB(0,0,255)) ;     // wide blue
 ltbluePen = CreatePen( PS_SOLID, 1, RGB(100,100,255)) ; // light blue
 plbluePen = CreatePen( PS_SOLID, 1, RGB(225,225,255)) ; // pale blue
 dkbluePen = CreatePen( PS_SOLID, 1, RGB(0,0,192)) ;     // dark blue
    redPen = CreatePen( PS_SOLID, 1, RGB(255,0,0)) ;     // red
  dkredPen = CreatePen( PS_SOLID, 1, RGB(136,0,0)) ;     // dark red
  ltredPen = CreatePen( PS_SOLID, 1, RGB(255,128,128)) ; // light red
   redWPen = CreatePen( PS_SOLID, 3, RGB(255,0,0)) ;     // wide red
 purplePen = CreatePen( PS_SOLID, 1, RGB(255,0,255)) ;   // purple
purpleWPen = CreatePen( PS_SOLID, 3, RGB(255,0,255)) ;   // purple
   cyanPen = CreatePen( PS_SOLID, 1, RGB(0,255,255)) ;   // blue-green (cyan)
  cyanWPen = CreatePen( PS_SOLID, 3, RGB(0,255,255)) ;   // blue-green (cyan)
  whitePen = CreatePen( PS_SOLID, 1, RGB(255,255,255)) ; // white
  greenPen = CreatePen( PS_SOLID, 1, RGB(0,192,0)) ;     // mid green
 greenWPen = CreatePen( PS_SOLID, 3, RGB(0,192,0)) ;     // wide mid green
dkgreenPen = CreatePen( PS_SOLID, 1, RGB(0,136,0)) ;     // dark green
ltgreenPen = CreatePen( PS_SOLID, 1, RGB(50,255,50)) ;	 // light green
  blackPen = CreatePen( PS_SOLID, 1, RGB(0,0,0)) ;       // black
 blackWPen = CreatePen( PS_SOLID, 3, RGB(0,0,0)) ;       // wide black
 yellowPen = CreatePen( PS_SOLID, 1, RGB(255,255,0)) ;   // yellow
yellowWPen = CreatePen( PS_SOLID, 3, RGB(255,255,0)) ;   // wide yellow
 orangePen = CreatePen( PS_SOLID, 1, RGB(255,128,64)) ;  // orange
   goldPen = CreatePen( PS_SOLID, 1, RGB(192,192,0)) ;   // gold
 dkgoldPen = CreatePen( PS_SOLID, 1, RGB(128,128,0)) ;   // dark gold
   grayPen = CreatePen( PS_SOLID, 1, RGB(192,192,192)) ; // gray
 dkgrayPen = CreatePen( PS_SOLID, 1, RGB(100,100,100)) ; // dark gray
 mdgrayPen = CreatePen( PS_SOLID, 1, RGB(200,200,200)) ; // medium gray
   palePen = CreatePen( PS_SOLID, 1, RGB(225,225,225)) ; // pale gray

 blkdotPen = CreatePen( PS_DOT  , 1, RGB(0,0,0)) ;       // black dotted
dkgrydotPen = CreatePen(PS_DOT, 1, RGB(100,100,100)) ;   // dark gray dotted
 reddotPen = CreatePen( PS_DOT,   1, RGB(255,0,0)) ;     // red dotted
dkgndotPen = CreatePen( PS_DOT,   0, RGB(0, 92,0)) ;     // dark green dotted

// Pens complementary to the above, for use in "ROP2" situations

   cbluePen = CreatePen( PS_SOLID, 1, RGB(255,255,0)) ;   // complement of blue
 cltbluePen = CreatePen( PS_SOLID, 1, RGB(155,155,0)) ;   // complement of light blue
 cplbluePen = CreatePen( PS_SOLID, 1, RGB(20,20,0)) ;	  // complement of pale blue
 cdkbluePen = CreatePen( PS_SOLID, 1, RGB(255,255,63)) ;  // complement of dark blue
    credPen = CreatePen( PS_SOLID, 1, RGB(0,255,255)) ;   // complement of red
  cdkredPen = CreatePen( PS_SOLID, 1, RGB(119,255,255)) ; // complement of dark red
  cltredPen = CreatePen( PS_SOLID, 1, RGB(0,128,128)) ;	  // complement of light red
 cpurplePen = CreatePen( PS_SOLID, 1, RGB(0,255,0)) ;     // complement of purple
   ccyanPen = CreatePen( PS_SOLID, 1, RGB(255,0,0)) ;     // complement of blue-green (cyan)
  cwhitePen = CreatePen( PS_SOLID, 1, RGB(0,0,0)) ;       // complement of white
  cgreenPen = CreatePen( PS_SOLID, 1, RGB(255,63,255)) ;  // complement of mid green
cdkgreenPen = CreatePen( PS_SOLID, 1, RGB(255,119,255)) ; // complement of dark green
cltgreenPen = CreatePen( PS_SOLID, 1, RGB(205,0,205)) ;	  // complement of light green
  cblackPen = CreatePen( PS_SOLID, 1, RGB(255,255,255)) ; // complement of black
 cyellowPen = CreatePen( PS_SOLID, 1, RGB(0,0,255)) ;     // complement of yellow
 cdkgoldPen = CreatePen( PS_SOLID, 1, RGB(0,0,128)) ;     // complement of dark gold
 notgoldPen = CreatePen( PS_SOLID, 1, RGB( 63, 63,255)) ; // not gold (complement of gold)
   cgrayPen = CreatePen( PS_SOLID, 1, RGB(63,63,63)) ;    // complement of gray
 cdkgrayPen = CreatePen( PS_SOLID, 1, RGB(155,155,155)) ; // complement of dark gray
   cpalePen = CreatePen( PS_SOLID, 1, RGB(30,30,30)) ;    // complement of pale gray

  wPixTypes = TWAIN_ANYTYPE;

SetErrorMode(SEM_NOOPENFILEERRORBOX) ;

     // Initialise Control Bitmaps

    InitBmControls() ;


	// Various useful constants

   onethird = 1.0 / 3.0 ;

         pi = 4.0 * atan(1.0) ;		//    calculate pi in radians (180 degrees)
	 quarpi =         pi / 4.0 ;	//      quarter pi (45  degrees)
     halfpi =         pi / 2.0 ;	//         half pi (90 degrees)
  thrhalfpi =   3.0 * pi / 2.0 ;	// three halves pi (270 degrees) 
      twopi =   2.0 * pi ;			//          two pi (360 degrees)
        r2d = 180.0 / pi ;			// convert radians to degrees & vice versa

	// Plotting versus Time

#define SSECOND 0
#define SMINUTE 1
#define   SHOUR 2
#define    SDAY 3
#define	  SWEEK 4
#define  SMONTH 5
#define   SYEAR 6

	tval[SSECOND] = SiSC =   1.0 ;					// seconds in a second (-:
	tval[SMINUTE] = SiMN =  60.0  * SiSC ;			// seconds in a minute
	tval[SHOUR]   = SiHR =  60.0  * SiMN ;			// seconds in an hour
	tval[SDAY]    = SiDY =  24.0  * SiHR ;			// seconds in a day (basic reference)
	tval[SWEEK]   = SiWK =   7.0  * SiDY ;			// seconds in a week
	tval[SMONTH]  = SiMO =  31.0  * SiDY ;			// seconds in a month of 31 days
	tval[SYEAR]   = SiYR = 365.25 * SiDY ;			// seconds in a julian year

    // Astronomical stuff.

 	       e0 =  ezero / r2d ;
	     edot =  ediff / r2d ;
	       g0 =  gzero / r2d ;
	     gdot =  gdiff / r2d ;
     radperhr =   15.0 / r2d ;
       oblong = longitude ;   // Nick's place
	    oblat = latitude ;
	  inplong = mylong ;	  // default user-enterable location
	   inplat = mylat ;		  // is Peterculter, Aberdeen, Scotland, UK.

    // Allocate memory for the elements and variations PELS structs.
    
    for ( i = 0 ; i < Planets + 1 ; i++ )
		  elvar[i] = (LPPELS)GlobalAlloc(GPTR, sizeof(PELS)) ;
	
    // Allocate memory for the ALIGN struct.
    
        align = (LPALIGN)GlobalAlloc(GPTR, sizeof(ALIGN)) ;
		align->found = 0 ;
   
    // Allocate for the alignment DATETIME structs
       
    for ( i = 0 ; i < MAXALS ; i++ )
	{
		for ( j = 0 ; j < Planets + 1 ; j++ )
		{
        Date_Time[j][i] = (LPDATETIME)GlobalAlloc(GPTR,sizeof(DATETIME)) ;
	 modDate_Time[j][i] = (LPDATETIME)GlobalAlloc(GPTR,sizeof(DATETIME)) ;
		}
	}

	getels() ;           // bring in the astronomical data

	nphases = GetPhases() ;

    // these are for hue and saturation calculations

       t0 = itan(-onethird, 2.0 * onethird) ;
	   tr = 0.0 ;
	    u = itan(-onethird, -onethird) ;
	   tb = adiff2(u, t0) ;
	    u = itan(2.0 * onethird, -onethird) ;
	   tg = adiff2(u, t0) ;

	// Validate use of ISource21.dll

	 _ISInitialize("{98F28E51-C24B-B1B4-9232-0080C8DA7A5E}") ;

	// validate use of ImgDLL

	//   ImgDLLStringInitDLL("{4EF99980-8EAE-11d2-922D-00104B307E04}") ;


	aRC[0] = rctl ;				// not used yet: maybe one day!
	aRC[1] = rclv ;

	Levels = dfault ;            // assume the default number of heights,
								 // but
	gpps(						 // get the most recently used number of 
		"Current Settings",		 // heights from the most recent session.
		"No. of measure levels",
		"Not Found",
		 buff,
		(DWORD)255,
		"bud32.bud"
		) ;
	 
	if (strcmp(buff,"Not Found") == 0)       // if nothing on record
	 {
		 sprintf( buff, "%2.2d", Levels ) ;	 // place the current number on record
		 wpps(			
			 "Current Settings",
			 "No. of measure levels",
			  buff,
			 "bud32.bud"
			 ) ;
	 }
	 else				// otherwise, see if recorded value is actually wanted
	 {
		char str[50] ;
		int Usersays ;
		int levs ;

		levs = atoi(buff) ;			 // the recorded value

		if (levs != dfault)
		{
         sprintf(str,
                 "%d heights on record.\n" \
                 "It is not the default (7).\n\n" \
                 "Do you want to use this number?", levs) ; 
		msgbox = 1 ;
		Usersays = MessageBox(NULL, str,"Non-Default Number of Measurement Heights", MB_YESNO) ;
		msgbox = 0 ;
		if (Usersays == IDYES) 
		Levels = levs ;		   // use the recorded number
		else				   // otherwise
		Levels = dfault ;	   // use the default
		}
		else
		Levels = dfault ;
	 }

	 {
		 char buff[255] ;

		gpps("SearchZone","Default","None", buff, (DWORD)255,"Bud32.bud") ; // the default search zone survives sessions
		if (strcmp(buff, "None")) strcpy(szSearchDir, buff) ;				// make it current
		wpps("SearchZone","Default", szSearchDir, "Bud32.bud") ;	// copy back to Bud32.bud, so the default zone survives the session
		SetDlgItemText(hArcDlg, IDC_E_SEARCHZONE, szSearchDir) ;	// fill the tell-tale
	 }

    // Create Windows

	hWndDesk = GetDesktopWindow() ;
	GetWindowRect(hWndDesk, &rcDesk) ;
	wwid = rcDesk.right - rcDesk.left ;
	whyt = rcDesk.bottom - rcDesk.top ;

 // This is the main window
 /*
    hWndCtrl = CreateWindow(
        "CtrlClass",                     // See RegisterClass() call.
        szCtrlWindowTxt,                 // Title bar text
        WS_OVERLAPPEDWINDOW,             // Top Level
		 5 * wwid / 100 ,
		 5 * whyt / 100 ,
		90 * wwid / 100 ,
		90 * whyt / 100 ,
        NULL,                            // Overlapped windows have no parent. 
	    NULL,                            // Use the window class menu.
        hInstance,                       // This instance owns this window.
        NULL                             // Pointer not needed.
    );
*/
	// use the whole screen
	    hWndCtrl = CreateWindow(
        "CtrlClass",                     // See RegisterClass() call.
        szCtrlWindowTxt,                 // Title bar text
        WS_OVERLAPPEDWINDOW,             // Top Level
		CW_USEDEFAULT ,
		CW_USEDEFAULT ,
		CW_USEDEFAULT ,
		CW_USEDEFAULT ,
        NULL,                            // Overlapped windows have no parent. 
	    NULL,                            // Use the window class menu.
        hInstance,                       // This instance owns this window.
        NULL                             // Pointer not needed.
    );
    // If window could not be created, return "failure"

    if (!hWndCtrl)
        return (FALSE);

	 hWndKnown[NumKnown++] = hWndCtrl ;

    ShowWindow(hWndCtrl, nCmdShow );    /* Show the window  */
	ShowWindow(hWndCtrl, SW_MAXIMIZE) ; /* Maximize it at once */
    GetClientRect( hWndCtrl, &rcctrl ) ;/* Get its client area */
    UpdateWindow(hWndCtrl);             /* Sends WM_PAINT message  */


 // This is the measurement window

 hWndBud = CreateWindow(
        "BudClass",                     /* See RegisterClass() call. */
        szBudWindowTxt1,                /* Text for window title bar.*/
        WS_CHILD|WS_CLIPSIBLINGS|
		WS_CAPTION|WS_SIZEBOX|
		WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
		WS_SYSMENU,                    
	    0,
		57,
		(rcctrl.right - rcctrl.left)/2,
		(rcctrl.bottom - rcctrl.top) - 57,
        hWndCtrl,                       /* child window's parent. */
        NULL,                           /* no menu.         */
        hInstance,                      /* This instance owns this window.    */
        NULL                            /* Pointer not needed.                */
    ) ;

    /* If window could not be created, return "failure" */

    if (!hWndBud)
        return (FALSE);

    hWndKnown[NumKnown++] = hWndBud ;
    GetClientRect(hWndBud, &rcb) ;


    /* Make the window visible; update its client area; and return "success" */

    ShowWindow(hWndBud, SW_SHOW);	/* Show the window                        */
    UpdateWindow(hWndBud);			/* Sends WM_PAINT message                 */

 // This is the Results window

 hWndRslt = CreateWindow(
        "ResultClass",                   
        szResWindowTxt,                  /* Text for window title bar.*/
	    WS_CHILD|WS_CLIPSIBLINGS|
		WS_CAPTION|WS_SIZEBOX|
		WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
		WS_SYSMENU,                    
		(rcctrl.right - rcctrl.left)/2,
		57,
		(rcctrl.right - rcctrl.left)/2,
		(rcctrl.bottom - rcctrl.top) - 57,
        hWndCtrl,                       
        NULL,                           /* no menu.         */
        hInstance,                      /* This instance owns this window.    */
        NULL                            /* Pointer not needed.                */
    ) ;

    /* If window could not be created, return "failure" */

    if (!hWndRslt)
        return (FALSE);
    hWndKnown[NumKnown++] = hWndRslt ;
    GetClientRect(hWndRslt, &rcrslt) ;

    /* Make the Result window visible; update its client area; */

    ShowWindow(hWndRslt, SW_SHOW);  /* Show the window */
    UpdateWindow(hWndRslt);         /* Sends WM_PAINT message */

  hWndLists = CreateWindow(
        "ListingClass",                  /* See RegisterClass() call. */
        "Listings",                      /* Text for window title bar.*/
	    WS_CHILD|WS_CLIPSIBLINGS|
		WS_CAPTION|WS_SIZEBOX|
		WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
		WS_SYSMENU,                    
		(rcctrl.right - rcctrl.left)/2,
		57,
		(rcctrl.right - rcctrl.left)/2,
		(rcctrl.bottom - rcctrl.top) - 57,
        hWndCtrl,                       
        NULL,                           /* no menu.         */
        hInstance,                      /* This instance owns this window.    */
        NULL                            /* Pointer not needed.                */
    ) ;

    /* If window could not be created, return "failure" */

    if (!hWndLists)
        return (FALSE) ;

    hWndKnown[NumKnown++] = hWndLists ;
    GetClientRect(hWndLists, &rclist) ;
	hWndTB = CreateAToolBar(hWndLists) ;
	
	// This is the Line Scan Graphs window.
	// It overlays the Results window.

    hWndScan = CreateWindow(
        "ScanClass",                /* See RegisterClass() call.*/
        szScanWindowTxt,            /* Title bar text */
	    WS_CHILD|WS_CLIPSIBLINGS|
		WS_CAPTION|WS_SIZEBOX|
		WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
		WS_SYSMENU,                    
		(rcctrl.right - rcctrl.left)/2,
		45,
		(rcctrl.right - rcctrl.left)/2,
		(rcctrl.bottom - rcctrl.top) - 45,
        hWndCtrl,                           /* parent. */
        NULL,                       /* Use the window class menu.         */
        hInstance,                  /* This instance owns this window.    */
        NULL                        /* Pointer not needed.                */
    );

    /* If window could not be created, return "failure" */

    if (!hWndScan)
        return (FALSE);

	 hWndKnown[NumKnown++] = hWndScan ;
     GetClientRect( hWndScan, &rcscan ) ;



 // This is the "Imagery" window.
 // Must be an overlapped window to have a menu.
 // Bloody nuisance!

 hWndAcq = CreateWindow(
        "AcqClass",
        "Imagery",                    /* Text for window title bar.*/
	    WS_OVERLAPPEDWINDOW,
        GetSystemMetrics(SM_CXSCREEN)/4, /* horizontal position.*/
        90,                              /* vertical position.*/
        GetSystemMetrics(SM_CXSCREEN)/2, /* width.*/
        GetSystemMetrics(SM_CYSCREEN) - 90, /* height.*/
        NULL,                           /* no parent. */
        NULL,                           /* Window's menu */
        hInstance,                      /* This instance owns this window.    */
        NULL                            /* Pointer not needed.                */
    ) ;

    /* If window could not be created, return "failure" */

    if (!hWndAcq)
        return (FALSE);

    hWndKnown[NumKnown++] = hWndAcq ;
    GetClientRect(hWndAcq, &rcacq) ;

 // This is the Null Profile Graph window.

 hWndNPGraf = CreateWindow(
        "Graphing",                      /* See RegisterClass() call. */
        "Null Profile (the profile y-axis is inverted)",
	    WS_CHILD|WS_CLIPSIBLINGS|
		WS_CAPTION|WS_SIZEBOX|
		WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
		WS_SYSMENU,                    
		rcctrl.left + 45,
		rcctrl.top + 110,
		(rcctrl.right - rcctrl.left) / 2 - 45,   // width
		rcctrl.bottom - rcctrl.top - 120,		 // height
        hWndCtrl,                       
        NULL,                           /* No menu							  */
        hInstance,                      /* This instance owns this window.    */
        NULL                            /* Pointer not needed.                */
    ) ;

    /* If window could not be created, return "failure" */

    if (!hWndNPGraf)
        return (FALSE);

	hWndKnown[NumKnown++] = hWndNPGraf ;
    GetClientRect(hWndNPGraf, &rcgraf) ;

// this is a window of my home-made buttons,
// (so that they can show my style of Tip)

hWndColl = CreateWindow(
        "CollateClass",            
        szCollWindowTxt,           
	    WS_POPUPWINDOW|WS_CAPTION|WS_SIZEBOX|WS_CLIPSIBLINGS,
		(rcb.right - rcb.left) - 100,
		20,
		(rcb.right - rcb.left)/2,
		100,
        hWndCtrl,  /* This child's parent */
        NULL,                      
        hInstance,                 
        NULL                       
    ) ;

    /* If window could not be created, return "failure" */

    if (!hWndColl)
        return (FALSE);

	hWndKnown[NumKnown++] = hWndColl ;
    GetClientRect(hWndColl, &rcoll) ;

hWndArch = CreateWindow(
        "ArchiveOps",              /* See RegisterClass() call. */
        szArchWindowTxt,           /* Text for window title bar.*/
	    WS_CHILD|WS_CLIPSIBLINGS|
		WS_CAPTION|WS_SIZEBOX|
		WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
		WS_SYSMENU,                    
		0,
		248,
		(rcctrl.right - rcctrl.left),
		(rcctrl.bottom - rcctrl.top) - 248,
        hWndCtrl,                                /* parent */
        NULL,                           /* Use the window class menu.         */
        hInstance,                      /* This instance owns this window.    */
        NULL                            /* Pointer not needed.                */
    ) ;

    /* If window could not be created, return "failure" */

    if (!hWndArch)
        return (FALSE);

	hWndKnown[NumKnown++] = hWndArch ;
    GetClientRect(hWndArch, &rcArc) ;


			hWndLayout = CreateWindow("PrintLayout",
			                      "Print Preview",
								   WS_OVERLAPPEDWINDOW,
								   3 * GetSystemMetrics(SM_CXSCREEN) / 8,
								   3 * GetSystemMetrics(SM_CYSCREEN) / 8,
								   7 * GetSystemMetrics(SM_CXSCREEN) / 16,
								   5 * GetSystemMetrics(SM_CYSCREEN) / 8,
								   NULL,
								   NULL,
								   hInst,
								   NULL
								  ) ;

			if (!hWndLayout) return FALSE ;
			GetClientRect(hWndLayout, &rclay) ;

		  hWndTune = CreateWindow("SelCurve",
			                      "Selectivity Curve",
								   WS_OVERLAPPEDWINDOW,
								   3 * GetSystemMetrics(SM_CXSCREEN) / 8,
								   3 * GetSystemMetrics(SM_CYSCREEN) / 8,
								   7 * GetSystemMetrics(SM_CXSCREEN) / 16,
								   5 * GetSystemMetrics(SM_CYSCREEN) / 8,
								   NULL,
								   NULL,
								   hInst,
								   NULL
								  ) ;

			if (!hWndTune) return FALSE ;
			GetClientRect(hWndTune, &rctune) ;

		 hWndRast =  CreateWindow("PGRaster",
								  "Events on Semi-Lunar Raster",
	                               WS_CHILD|WS_CLIPSIBLINGS|
		                           WS_CAPTION|WS_SIZEBOX|
		                           WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
		                           WS_SYSMENU,
								   (rcctrl.right - rcctrl.left)/2,
								   45,
								   (rcctrl.right - rcctrl.left)/2,
								   (rcctrl.bottom - rcctrl.top) - 45,
								   hWndCtrl,
								   NULL,
								   hInst,
								   NULL
								   ) ;

			if (!hWndRast) return FALSE ;
			GetClientRect(hWndRast, &rcrast) ;
			
			hFlag = LoadBitmap(hInstance,MAKEINTRESOURCE(IDB_BUD_FLAG)) ;

			{
				double asp ;
				int cx, cy, ofx, ofy, w, h ;

		cx = GetSystemMetrics(SM_CXSCREEN) ;
		cy = GetSystemMetrics(SM_CYSCREEN) ;
	   ofx = cx / 3 ;
	   ofy = cy / 8 ;
	     w = cx / 3 ;
       asp = 250.0 / 320.0 ;
	     h = (int)((double)w * asp) ; 


hWndFlag = CreateWindow(
        "FlagClass",
        NULL,
        WS_POPUP|WS_BORDER,
        ofx,
        ofy,
          w,
          h,
        hWndCtrl,                    
        NULL,
        hInstance,
        NULL 
    );
			}
    /* If window could not be created, return "failure" */

    if (!hWndFlag)
        return (FALSE);

	hWndKnown[NumKnown++] = hWndFlag ;
    GetClientRect( hWndFlag, &rcflag ) ;

    // Show the sign on banner.

    ShowWindow(hWndFlag, SW_SHOW );         // Show the window
    UpdateWindow(hWndFlag);                 // Sends WM_PAINT message
	banner = 1 ;

    // Initialise Menu checking
    hmenu = GetMenu(hWndCtrl) ;

	// Disable "Details" Item. (Re-enabled when file available)
	EnableMenuItem(hmenu,1,MF_BYPOSITION|MF_GRAYED) ;
 	DrawMenuBar(hWndCtrl) ;

    // Set up a 4 second timer for banner display
	// This will destroy the banner window, the
	// banner's handle, and itself, four seconds
	// after it starts up.
    Tim = SetTimer(hWndCtrl, IDT_BANNER_TIMER, Interval, NULL ) ;

	//allocate room for data  
  for (i = 0 ; i < 200 ; i++ )
  {
	   DimenCombo[i] = (char *)GlobalAlloc(GPTR,80) ;
	  ResultCombo[i] = (char *)GlobalAlloc(GPTR,80) ;
  }

  /***** Establish Common Dialog File Selection facility *****/
  
  // look for the most recently used directory

  gpps(
	  "Last File in Work",
	  "LastDir",
	  "No Dir",
	  szDirName,
	  180,
	  "bud32.bud"
	  ) ;
	 
  if (strcmp(szDirName,"No Dir") == 0)        // if no previous directory,
    strcpy(szDirName,"c:\\" ) ;               // use default directory

    szFile[0] = '\0' ;

    if((cbString = LoadString(hInstance,IDS_FILEFILT1,
                              szFilter,
                              sizeof(szFilter))) == 0 )
    			      goto nofilter; /* should have an error handler */

/* Deal with "Wild Character" in Filter String resource */
    chReplace = szFilter[cbString-1] ;
    for ( i = 0 ; szFilter[i] != '\0' ; i++ )
        if (szFilter[i] == chReplace ) szFilter[i] = '\0' ;


    if((cbString = LoadString(hInstance,IDS_FILEFILT2,
                              szCollFilter,
                              sizeof(szCollFilter))) == 0 )
    			      goto nofilter; /* should have an error handler */

/* Deal with "Wild Character" in Filter String resource */
    chReplace = szCollFilter[cbString-1] ;
    for ( i = 0 ; szCollFilter[i] != '\0' ; i++ )
        if (szCollFilter[i] == chReplace ) szCollFilter[i] = '\0' ;

/* Set all members of the OPENFILENAME struct to zero */
      memset( &ofn,0,sizeof(OPENFILENAME) ) ;

/* Fill in the "permanent" members of the struct */
	ofn.lStructSize     = sizeof(OPENFILENAME) ;
	ofn.hwndOwner       = NULL ;
	ofn.hInstance       = hInst ;
	ofn.nFilterIndex    = 1 ;
	ofn.lpstrInitialDir = szDirName ;
	ofn.lpstrDefExt     = "jpg" ;
    ofn.lpstrTitle      = "Open a Bud File" ;
    ofn.Flags           = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST  ;


// ************************************** LAUNCH *******************************
// Open the Archivist immediately after the banner display
//
/**** 21st Oct. 2010 -- the program is now launched by the banner timer

      COL = 1 ;
	while (!SetWindowPos(hWndColl, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_SHOWWINDOW)) ;
		SendMessage(hWndColl, WM_COMMAND, IDM_ARCHIVIST1, 0L) ;
		UpdateWindow(hArcDlg) ;

	hWndTreeSer = GetDlgItem(hArcDlg, IDC_TREECTL_SER) ;	// get the handle of the per series tree view
	InitTreeViewImageLists(hWndTreeSer) ;					// initialise the per series tree view image list

	hWndTreeExp = GetDlgItem(hArcDlg, IDC_TREECTL_EXP) ;	// get the handle of the "experimental" tree view
	InitTreeViewImageLists(hWndTreeExp) ;					// initialise the "experimental" tree view image list

	hWndTreeArc = GetDlgItem(hArcDlg, IDC_TREECTL_ARC) ;	// get the handle of the Archives tree view
	InitTreeViewImageLists(hWndTreeArc) ;					// initialise the Archives tree view image list

// Find what allowed drives are available on the system.
	numdrv = FindDrives(hArcDlg) ;
****/
nofilter:;

	return (TRUE) ;
}

// 15/08/2016 : an experiment --- which worked!

LPITEMIDLIST PidlBrowse(HWND hwnd, int nCSIDL, LPSTR pszDisplayName)
{
    LPITEMIDLIST pidlRoot = NULL;
    LPITEMIDLIST pidlSelected = NULL;
    BROWSEINFO bi = {0};

    if(nCSIDL)
    {
        SHGetFolderLocation(hwnd, nCSIDL, NULL, NULL, &pidlRoot);
    }

    else
    {
        pidlRoot = NULL;
    }

    bi.hwndOwner = hwnd;
    bi.pidlRoot = pidlRoot;
    bi.pszDisplayName = pszDisplayName;
    bi.lpszTitle = "Please Pick a Bud Archive";
    bi.ulFlags = 0;
    bi.lpfn = NULL;
    bi.lParam = 0;

    pidlSelected = SHBrowseForFolder(&bi);

	if (pidlSelected)
	{
		SHGetPathFromIDList(pidlSelected, szSearchDir) ;
	}

    if(pidlRoot)
    {
        CoTaskMemFree(pidlRoot);
    }

    return pidlSelected;
}

/* Use the Common Dialog File Fetch facility */

BOOL GetBudFile(HWND hWnd)
{
  BOOL status ;

  ofn.lpstrInitialDir = szDirName ;

  if (OpeninImagery)
  {
   ofn.lpstrFile       = szImageryFile ;
   ofn.nMaxFile        = sizeof(szImageryFile) ;
  }
  else
  {
   ofn.lpstrFile       = szFile ;
   ofn.nMaxFile        = sizeof(szFile) ;
  }

  ofn.lpstrFilter     = szFilter ;
  ofn.lpstrTitle      = "Open a Bud File" ;
  ofn.lpstrFileTitle  = szFileTitle ;
  ofn.nMaxFileTitle   = sizeof(szFileTitle) ;
  ofn.hwndOwner       = hWnd ;

  if (showtips)
	  if (CurrentTip != (HWND) NULL) RemoveTip() ;


  status = (GetOpenFileName(&ofn)) ; // return TRUE for file-selected,
                                     // FALSE otherwise

  //switch default path to the latest selected
  if (status == TRUE && !OpeninImagery) strcpy(szDirName, FetchPath(szFile)) ;

	return (status) ;
}

BOOL GetSearchFolder(HWND hWnd)
{
  BOOL status ;

  ofn.lpstrInitialDir = "C:\\" ;

  ofn.lpstrFile       = szDummyFile ;		// this receives qualified file name
  ofn.nMaxFile        = sizeof(szDummyFile) ;

  ofn.lpstrFilter     = szFilter ;
  ofn.lpstrTitle      = "Click any Image at the Root of the Target Folder Group." ;
  ofn.lpstrFileTitle  = szFileTitle ;
  ofn.nMaxFileTitle   = sizeof(szFileTitle) ;
  ofn.hwndOwner       = hWnd ;

  if (showtips)
	  if (CurrentTip != (HWND) NULL) RemoveTip() ;


  status = (GetOpenFileName(&ofn)) ; // If the selection succeeds, status is TRUE 
                                     
  //switch default path to the latest selected
  if (status == TRUE ) strcpy(szSearchDir, FetchPath(szDummyFile)) ;

	return (status) ;
}

BOOL SaveBudFile(HWND hWnd)
{
  BOOL status ;

  ofn.lpstrInitialDir = szDirName ;

  if (SavefromImagery)	// write incoming file path to szImageryFile
  {
   ofn.lpstrFile       = szImageryFile ;
   ofn.nMaxFile        = sizeof(szImageryFile) ;
  }
  else					// write incoming file path to szFile
  {
   ofn.lpstrFile       = szFile ;
   ofn.nMaxFile        = sizeof(szFile) ;
  }
  
  ofn.lpstrFilter     = szFilter ;
  ofn.lpstrTitle      = "Save a Bud Image" ;
  ofn.nMaxFileTitle   = sizeof(szFileTitle) ;
  ofn.hwndOwner       = hWnd ;

  status = (GetSaveFileName(&ofn)) ; // return TRUE for file-selected,
                                     // FALSE otherwise
  
  //switch default path to the latest selected (into workshop)
  if (status == TRUE && !SavefromImagery) strcpy(szDirName, FetchPath(szFile)) ;

	return (status) ;
}

BOOL SaveCollFile(void)
{
  BOOL status ;

  ofn.lpstrInitialDir = szCollDir ;
  ofn.lpstrFile       = szCollFile ;
  ofn.nMaxFile        = sizeof(szCollFile) ;
  ofn.lpstrFilter     = szCollFilter ;
  ofn.lpstrFileTitle  = szFileTitle ;
  ofn.lpstrTitle      = "Save Collation File" ;
  ofn.nMaxFileTitle   = sizeof(szFileTitle) ;

  status = (GetSaveFileName(&ofn)) ; // return TRUE for file-selected,
                                     // FALSE otherwise
  
	return (status) ;
}

void GrabFrame( void )
{
						static SYSTEMTIME stm ;
						char   path[256] ;
						char  path1[256] ;
						char  Epoch[50]  ;
						char   Name[80]  ;
						 int  Year ;

					// respond to timer if not busy
					if (!grabbusy) 
					{
						grabbusy = 1 ; // we've responded, so we're busy now!

						if(!capGrabFrameNoStop(hWndGrb)) // try a grab
						{
						grabbusy = 0 ;  // OK, didn't, so just drop through, 
						//break ;			// but allow further tries
						}
						else			// got it!
						{
							if (UseLocalTime)
						GetLocalTime(&stm) ;	// use local time
						else
						GetSystemTime(&stm) ;	// use GMT (UTC)

						Year = (int)stm.wYear ;
						// Time travellers, are we?
						Year = (Year >= 2000) ? Year - 2000 : Year - 1900 ;

						// The time part of the file name
						sprintf(Epoch,"%2.2d%2.2d%2.2d%2.2d%2.2d%2.2d",
								(int)stm.wDay,
								(int)stm.wMonth,
								     Year,
								(int)stm.wHour,
								(int)stm.wMinute,
								(int)stm.wSecond
								) ;
						// form the file name
						sprintf(Name, "%s%s", GrabPrefix, Epoch) ;
						// show it in the Edit box
						SetDlgItemText(hDlgGrabSetUp, IDC_E_GRAB_NAME, Name) ;
						sprintf(path, "%s%s.bmp", GrabDir, Name) ; // for the BMP
						capFileSaveDIB(hWndGrb, path) ;

				// This works, but *.bmp takes far too much storage, so the next thing would be to 
				// open the saved name.bmp, convert it to name.jpg, save name.jpg, then close
				// and delete name.bmp. Try this (saving the BMP in the same Dir as the JPG) ----

						sprintf(path1,"%s%s.jpg", GrabDir, Name) ; // to save the JPG

						BMPtoJPG(path, path1) ;		// OK! It works.
					}

					if (grabbeeps)
					MessageBeep(MB_OK) ;

					// alright, we seem to be ready for another
					grabbusy = 0 ;
					}
}

/*********************************************************************/
long CALLBACK CtrlWndProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
	        HDC hdc, hmemDC ;
    PAINTSTRUCT ps ;
         BITMAP bm ;
        HBITMAP OBm ;
static OFSTRUCT of, of1 ;
	      HFILE hbud ;
          POINT pt ;
  static  POINT box, cpt, cupt, tpt ;
  static  HFILE hUp ;
  static double eptemp ;
  static   char szFileName[255] ;

   static char buff[255] = "\0" ;
 unsigned char string[100] ;
    static     Btn ;
    static int i, user_says ;
	static int OPF = 0, XIT = 0, CMT = 0, ACQ = 0 ;
	static int PRV = 0, NXT = 0, SLA = 0, SVI = 0 ;
           int ftyp ; // UserSays

    switch (message)
	{
        case WM_COMMAND:       /* message: command from application menu */
              {
                switch (LOWORD(wParam))
                {
				  case WM_MOUSEGONE:
		              if (CurrentTip != (HWND)NULL)
			          RemoveTip() ;
		              return 0L ;
					  break ;

				  case IDM_WORKSHOP_HELP:
					  WinHelp(hWnd,"Bud32a.hlp", HELP_CONTENTS, 0L) ;
					  return 0L ;
					  break ;

				  case IDM_ABOUT:
					  DialogBox(hInst,
						        MAKEINTRESOURCE(IDD_ABOUT),
						        NULL,
						        AboutProc) ;
					  break ;

				  case IDM_ARCHIVIST1:
					  SendMessage(hWndColl, WM_COMMAND, IDM_ARCHIVIST, 0L) ;
					  break ;

				  case IDM_DIRECT_MEASURE:
				// record XY co-ordinates of image-points in a list.

					  DoDirectMeasure ^= 1 ;

					  MessageBox(NULL,
						         "Sorry, not yet implemented.",
						         "Direct XY measurement",
								 MB_ICONINFORMATION|MB_OK
								 ) ;

					  if (DoDirectMeasure)
						  CheckMenuItem(GetMenu(hWnd), IDM_DIRECT_MEASURE, MF_BYCOMMAND|MF_CHECKED) ;
					  else
						  CheckMenuItem(GetMenu(hWnd), IDM_DIRECT_MEASURE, MF_BYCOMMAND|MF_UNCHECKED) ;

					  break ;

 				  case IDM_M_GRAB_SETUP:
					TGR ^= 1 ;	  
					ivrc(hWnd, &rctl[Tgr], TRUE) ;
				if (TGR)
				{
				if (hDlgGrabSetUp == (HWND)NULL)
					hDlgGrabSetUp = CreateDialog(
						hInst,
						MAKEINTRESOURCE(IDD_GRAB_SETUP),
						hWndRslt,
						GrabSetUpDlg ) ;

					ShowWindow(hDlgGrabSetUp,SW_SHOW) ;
					BringWindowToTop(hDlgGrabSetUp) ;
					CheckMenuItem(GetMenu(hWnd), IDM_M_GRAB_SETUP, MF_BYCOMMAND|MF_CHECKED) ;
					grabwindow = 1 ;
				}
				else
				{
					ShowWindow(hDlgGrabSetUp, SW_HIDE) ;		   // hide dialogue
					CheckMenuItem(GetMenu(hWnd), IDM_M_GRAB_SETUP, MF_BYCOMMAND|MF_UNCHECKED) ;
					grabwindow = 0 ;
				}
					  break ;

				  case IDM_GRAB_ONE:		// Space bar pressed
					  if (grabwindow)
					  GrabFrame();
					  break;

				  case IDM_TIMED_GRAB:		// F10 pressed.
				  case IDM_M_GRAB:			// Menu

					  timed_grab ^= 1 ;

					  if (timed_grab)
					  {
						GrabmS = (UINT)(1000 * (GrabMins * 60 + GrabSecs)) ;	// calculate interval
						SetTimer(hWnd, IDT_GRAB_TIMER, GrabmS, NULL) ;			// start timer (start grabbing)
						grabbing = 1 ;
						CheckMenuItem(GetMenu(hWnd), IDM_M_GRAB, MF_BYCOMMAND|MF_CHECKED) ;

						// change button legend to "Stop"
						SendDlgItemMessage(hDlgGrabSetUp,
						IDC_B_GRAB_START,
						WM_SETTEXT,
						(WPARAM)0,
						(LPARAM)(LPCTSTR)grabgo[1]) ;						
					  }
					  else
					  {
						  KillTimer(hWnd, IDT_GRAB_TIMER) ;		// stop timer (stop grabbing)
						  grabbing = 0 ;
						  CheckMenuItem(GetMenu(hWnd), IDM_M_GRAB, MF_BYCOMMAND|MF_UNCHECKED) ;

						// change button legend to "Go"
						SendDlgItemMessage(hDlgGrabSetUp,
						IDC_B_GRAB_START,
						WM_SETTEXT,
						(WPARAM)0,
						(LPARAM)(LPCTSTR)grabgo[0]) ;						
					  }

					  break ;

	   case IDM_CAPTURE_NOW:  // F12 was pressed
		   if (capture)		  // The "capture" button was clicked
		   {
			   POINT pt_cap ;
			  UINT32 w, h ;
			     HDC hDC ;

			   // if the mouse is now clicked on a window..
			 if ((hWndCapt = SelectWindow(hWnd)) == (HWND)NULL) 
			 {
				 // didn't work. Report and forget.
				 msgbox = 1 ;
				 MessageBox(NULL,
					 "Selection Failed",
					 "Window Selection", MB_OK) ;
				 msgbox = 0 ;
				 break ;
			 }
			 // and if it works..

			// get rid of any former HBITMAP
			   if (hCapt != (HBITMAP)NULL)
			   {
				  DeleteObject(hCapt) ;
			      hCapt = NULL ;
			   }

			 // do the actual capture to HBITMAP
		    hCapt = Capture(hWndCapt, &pt_cap) ;

			// get dimensions
			    w = (UINT32)pt_cap.x ;
			    h = (UINT32)pt_cap.y ;

			 // be sure of clear ground for RGB. GlobalSize()
			 // returns zero on a non-valid handle.
				if (GlobalSize(newbuf)) GlobalFree(newbuf) ;


			// convert the HBITMAP to RGB buffer

			   hDC = GetDC(hWndAcq) ;

			   newbuf = _ISHBITMAPToRGB
							(
							  hCapt,
							  &w,
							  &h,
							  hDC,
							  NULL
							) ;

			   ReleaseDC(hWndAcq, hDC) ;

		   if (newbuf) // if conversion works,
		   {
			   DeleteObject(hCapt) ;       // get rid of HBITMAP
			   pnewbuf = (BYTE *) newbuf ; // get pointer
			 HaveImage = 1 ;			   // 
			 Previewed = 0 ;			   // this is for the printer
			  acquired = 0 ;			   // not a TWAIN operation
			   nBright = nContrast = 500 ; // defaults first (for scrolls)
			   fBright = fContrast = 0.0 ;
			     w_now = w ;   // copy dims to globals
			     h_now = h ;
			  captured = 1 ;   // is captured
			       CAP = 0 ;   // not capturing now (for button state)
			   capture = 0 ;   // ditto (for program)
			   ivrc(hWndCtrl, &rctl[Cap], TRUE) ; // lift button
			   ivrc(hWndAcq, NULL, TRUE) ; // show the capture
		   }
		   else
		   {
			HaveImage = 0 ;  // didn't work
			 captured = 0 ;	 // not captured
			 capture  = 0 ;	 // not capturing
		   }
		   }

		   break ;


				  case IDM_TWAIN_ACQUIRE:
				// toggle 'acquire' button.EnumWindows
				ACQ ^= 1 ;
				ivrc(hWnd, &rctl[Acq], TRUE) ;
				//UpdateWindow(hWnd) ;

				// show/hide the acquisition window
				if (ACQ)
				{
			      ShowWindow(hWndAcq, SW_SHOW) ;
				SetWindowPos(hWndAcq, HWND_TOP,
					         0,0,0,0,
							 SWP_NOSIZE|SWP_NOMOVE) ;
			  ivrc(hWndAcq,NULL,TRUE) ;
				}
				else
				ShowWindow(hWndAcq, SW_HIDE) ;
					  break ;

                  case IDM_EXIT:					// SHUT DOWN
				  case WM_CLOSE:
			   sprintf(buff,"%2.2d",Levels) ;
			   wpps(
				   "Current Settings",
				   "No. of measure levels",
				    buff,
				   "bud32.bud"
				   );

			   sprintf(buff,"%2.2d", dfault) ;
			   wpps(
				   "Current Settings",
				   "Default No. of measure levels",
				    buff,
				   "bud32.bud"
				   );

			   if (gotimage)
					{
				      static char *s[] = {"Yes", "No"} ;
					          int  n ;
						  LPSUITE  ps ;

					if (toArchive)
					{
						strcpy(szArchFile, szFile) ;
						SaveAllAway() ;
					}

				      if (StandardBudImage)
					  {
				    wpps(
						"Last File in Work",
						"LastFile",
						 DropPath(szFile),
						 "bud32.bud" ) ;

					wpps(
						"Last File in Work",
						"LastDir",
						 szDirName,
						 "bud32.bud" ) ;

					wpps(
						"Last File in Work",
						"LastArchive",
						 szUsingArchive,
						 "bud32.bud" ) ;

					ps = A.pSuiteperpfx[CurrentPfxID][UseSuite] ;

					if (ps != (LPSUITE)NULL)
					wpps(
						"Last File in Work",
						"LastArchiveOpSuite",
						 ps->desc, 
						 "bud32.bud" ) ;
					else
					wpps(
						"Last File in Work",
						"LastArchiveOpSuite",
						 "", 
						 "bud32.bud" ) ;

					ps = A.pSuiteperpfx[BudPfxID][UseSuite] ;

					if (ps != (LPSUITE)NULL)
					wpps(
						"Last File in Work",
						"LastInstanceSuite",
						 ps->desc, 
						 "bud32.bud" ) ;
					else
					wpps(
						"Last File in Work",
						"LastInstanceSuite",
						 "", 
						 "bud32.bud" ) ;

					n = (RecallMRI) ? 0 : 1 ;

					wpps(
						"Last File in Work",
						"Recall Most Recent",
						 s[n],
						"bud32.bud" ) ;
					  }
					}

			   WinHelp(hWnd,"Bud32.hlp",HELP_QUIT,(DWORD)NULL) ;
               DestroyWindow(hWndBud ) ;
               DestroyWindow(hWndScan) ;
			   DestroyWindow(hWndFlag) ;
			   DestroyWindow(hWndRslt) ;
			   DestroyWindow(hWndColl) ;
			   DestroyWindow(hWndArch) ;
			   DestroyWindow(hWndTune) ;
			   DestroyWindow(hWndView) ;
			   DestroyWindow(hWndLists) ;
		       DestroyWindow(hWnd) ;
			      return 0L ;

				  case IDM_SHOW_DETAILS:

 			   DialogBox(hInst,
					     MAKEINTRESOURCE(IDD_DETAILS),
					     hWnd,
						 DetailDlgProc) ;
				  break ;

				  case IDM_SET_PREFS:

				DialogBox(hInst,
					      MAKEINTRESOURCE(IDD_PREFS_NEW),
						  hWnd,
						  PrefsDlgProc) ;
				  break ;

				  case IDM_REMOVE_TRK_FILE:
					  if (gotimage)
					  {
						  char name[100] ;

					   strcpy(name, DropPath(szTrkPath)) ;

					   // check if a standard bud file
						 if (
							 ParseBudID(name, &Lose_Files) == TRK
							)
							{
	  if ((htrack = OpenFile(szTrkPath,&of,OF_EXIST)) != HFILE_ERROR)
					htrack = OpenFile(szTrkPath,&of,OF_DELETE) ;
	                
			  UpdatingRecords = 1 ;
	          SendMessage(hWndCtrl,WM_COMMAND,IDM_OPEN_FILE,0L) ;
			  UpdatingRecords = 0 ;
						    }
						 else  
							{	 // No records to remove.
								char bf[100] ;

								sprintf(bf,
									"%s is not a standard Bud File." \
							    "\n\nThere is no .TRK file to Remove.",
								       name) ;
								msgbox = 1 ;
								MessageBox(NULL,
									       bf,
										  ".TRK Removal",
										   MB_ICONEXCLAMATION|MB_OK) ;
								msgbox = 0 ;
							}
					  }
					  else
					  {
						  msgbox = 1 ;
						  MessageBox(NULL,
						             "No Instance is loaded.",
									 "Track File Removal.",
									  MB_ICONEXCLAMATION|MB_OK) ;
						  msgbox = 0 ;
					  }
					  break ;

				  case IDM_REMOVE_INSTANCE:

					  if (gotimage)
					  {
						  char name[256] ;

						  strcpy( name, DropPath(szFile)) ;

					   // check if a standard bud image file
						 if (
							 ParseBudID(szFile, &Lose_Files) == IMG
							)
							{
							 int UserSays ;
				// if an .ini file exists, delete it.

      if ((hbud = OpenFile(szIniPath,&of,OF_EXIST)) != HFILE_ERROR)
	  {
		  UserSays = MessageBox(NULL, "Are you sure you want to delete the INI?", "INI deletion.", MB_YESNO);

					if (UserSays == IDYES) hbud = OpenFile(szIniPath,&of,OF_DELETE) ;
	  }
		else
			MessageBox(NULL, "There is no INI", "INI deletion", MB_OK);


	            // if a .dat file exists, delete it.

      if ((hdat = OpenFile(szDatPath,&of,OF_EXIST)) != HFILE_ERROR)
	  {
		  UserSays=MessageBox(NULL, "Are you sure you want to delete the DAT?", "DAT deletion.", MB_YESNO);
	  
					if(UserSays == IDYES) hdat = OpenFile(szDatPath,&of,OF_DELETE) ;
	  }
		else
			MessageBox(NULL, "There is no DAT", "DAT deletion", MB_OK);



				// If a .trk file exists, delete it.

	  if ((htrack = OpenFile(szTrkPath,&of,OF_EXIST)) != HFILE_ERROR)
	  {
		  UserSays=MessageBox(NULL, "Are you sure you want to delete the TRK?", "TRK deletion.", MB_YESNO);

					if(UserSays == IDYES) htrack = OpenFile(szTrkPath,&of,OF_DELETE) ;
	  }
		else
			MessageBox(NULL, "There is no TRK", "TRK deletion", MB_OK);



			  if (calibrated)
	          ResetCalibration() ;

			  UpdatingRecords = 1 ;
	          SendMessage(hWndCtrl,WM_COMMAND,IDM_OPEN_FILE,0L) ;
			  UpdatingRecords = 0 ;

							}
							else // Not a standard bud file.
							{	 // No records to remove.
								char bf[100] ;

								sprintf(bf,
									"%s is not a standard Bud File." \
							    "\n\nThere are no Records to Remove.",
								       name) ;
								msgbox = 1 ;
								MessageBox(NULL,
									       bf,
										  "Instance Removal",
										   MB_ICONEXCLAMATION|MB_OK) ;
								msgbox = 0 ;
							}
					  }
					  else
					  {
						  msgbox = 1 ;
						  MessageBox(NULL,
						             "No Instance is loaded.",
									 "Instance Removal.",
									  MB_ICONEXCLAMATION|MB_OK) ;
						  msgbox = 0 ;
					  }
					  break ;


				  case IDM_REMOVE_ALL_BUD: // not implemented
					  break ;			   // probably too dangerous!

				  case IDM_M_GPS:
				// this shows/hides the currently-skeletal GPS dialog box 
					  GPS ^= 1;
					  ivrc(hWnd,&rctl[Gps],TRUE) ;
					  if (hDlgGPS)
					  {
						  if (GPS)
						  {
							  ShowWindow(hDlgGPS, SW_SHOW) ;
							  BringWindowToTop(hDlgGPS) ;
						  }
						  else
							  ShowWindow(hDlgGPS, SW_HIDE) ;
					  }
					  break ;

				  case IDM_COLLATE_DATA:
                  COL ^= 1 ;
			      Collate = COL ;
                  ivrc(hWnd,&rctl[Col],TRUE) ;
				  if (Collate)
				  {
			    	ShowWindow(hWndColl, SW_SHOW) ;
					SetWindowPos(hWndColl, HWND_TOP,
						         0,0,0,0,
								 SWP_NOMOVE|SWP_NOSIZE) ;
			    	UpdateWindow(hWndColl) ;
			      }
			    	else
	    			ShowWindow(hWndColl, SW_HIDE) ;
					  break ;

				  case IDM_SELECT_SUITE:

						  DialogBox(hInst,						// go pick a suite
									MAKEINTRESOURCE(IDD_LOAD),
									hWnd,
									PickSuiteDlgProc
									) ;
					  break ;

				  case IDM_PREV_FILE:		// Left click in button
				  case PREV_INST:			// Alt + left arrow
			if (!searched)
			{
				int UserSays ;
				char str[300] ;

				sprintf(str,
"To allow the Sequencer to function,\n" \
"the Bud Workshop would need to scan the system\n" \
"to find and list the validly-named image-files\n" \
"currently on this system.\n\n" \
"Do you wish this to happen now?"
						) ;

				UserSays = MessageBox(NULL,	str, "The Sequencer has no Data.",
										MB_YESNO|MB_ICONEXCLAMATION) ;

				if (UserSays == IDYES)
				{
					SendMessage(hWndColl, WM_COMMAND, IDM_ARCHIVIST, 0L) ;
					goto sequ ;
				}
				else
					break ;
			}

sequ:	if (searched && gotimage)
			{
			// Now attempting to use the Archivist data base for this purpose, as it
			// ought to be independent of the image file's location, and should allow
			// any (ascending) distribution of epochs. We start with the image and
			// epoch currently loaded in the BW.

				char szInst[100] ;
				int i, index, iPfxID, iImgID, iPathID ;

				strcpy(szInst, DropPath(szFile)) ;

				if (ParseBudID(szFile, &ToFro) == IMG) // is loaded, so szFile must exist!
				{
				// find this prefix ID number among those currently on the system.
				for (i = 0 ; i < A.iPfxIDs ; i++)
				{
					if (!_stricmp(ToFro.Prefix, A.szKnownpfx[i]))
					{
						iPfxID = i ;
						break ;
					}
				}

				// find the Instance ID number of the incumbent image, among those
				// known in ascending time order to the current prefix.
				for (i = 0 ; i < A.iNumImgperpfx[iPfxID] ; i++)
				{
					iImgID = A.Imgperpfx[iPfxID][i] ;
					if (!_stricmp(szInst, A.szKnownimg[iImgID]))
					{
						index = i ;
						break ;
					}
				}

				// if we have not reached the start of the list, i.e, the earliest,
				// then we want the instance before the current one
				if (index) 
				{
					LPSUITE sui ;
					  int pthord ;

					iImgID = A.Imgperpfx[iPfxID][index - 1] ;

						   sui = A.pSuiteperpfx[iPfxID][UseSuite] ; // Ok, is using the right reference
					    pthord = sui->iIMGpth ;

					   iPathID = A.iPthIDperimg[iImgID][pthord] ;

				// copy the path to the file
					strcpy(szFileName, A.szKnownpth[iPathID]) ;
				// strcat the file name
					strcat(szFileName, A.szKnownimg[iImgID]) ;
				// is it there?
					if ((hUp = OpenFile(szFileName, &of1, OF_EXIST)) != HFILE_ERROR)
					{
				// it's there, so archive incumbent's details
						if (toArchive)
						{
						strcpy(szArchFile, szFile) ; // copy incumbent file's name
						SaveAllAway() ;
						}

		        // Load the file in the usual fashion.
					strcpy(szFile, szFileName) ;
					Sequencing = 1 ;
					SendMessage(hWndCtrl, WM_COMMAND, IDM_OPEN_FILE, 0L) ;
					Sequencing = 0 ;
					}
					else // image is not on given path: say so
					{
						MessageBox(NULL,
							"Image file not found on the given path",
							"Backwards Sequencing", MB_OK) ;
					}
				}
				 else // say we've bottomed out, then just drop through (but save previous anyway)
					{
						if (toArchive)
						{
						strcpy(szArchFile, szFile) ; // copy incumbent file's name
						SaveAllAway() ;
						}
						batching = 0 ;			// if we have been batching, say we're done
						MessageBox(NULL,
							"No earlier Image files are available.",
							"Backwards Sequencing", MB_OK) ;
					}
				}
				else
				MessageBox(NULL, "Not a validly-named Image", "Backwards Sequencing", MB_OK) ;
			}
						break ;

			case IDM_NEXT_FILE: // Left click in button
			case NEXT_INST:		// Alt + Right arrow
			if (!searched)
			{
				 int UserSays ;
				char str[300] ;

				sprintf(str,
"To allow the Sequencer to function,\n" \
"the Bud Workshop would need to search the system\n" \
"to find and list the validly-named image-files\n" \
"currently on the system.\n\n" \
"Do you wish this to happen now?"
						) ;

				UserSays = MessageBox(NULL,	str, "The Sequencer has no Data.",
										MB_YESNO|MB_ICONEXCLAMATION) ;

				if (UserSays == IDYES)
				{
					SendMessage(hWndColl, WM_COMMAND, IDM_ARCHIVIST, 0L) ;
					goto sequ1 ;
				}
				else
					break ;
			}

sequ1:		if (searched && gotimage)
			{
			// Now attempting to use the Archivist data base for this purpose, as it
			// ought to be independent of the image file's location, and should allow
			// any (ascending) distribution of epochs. We start with the image and
			// epoch currently loaded in the BW.

				char szInst[100] ;
				int i, n, index, iPfxID, iImID, iImgID, iPathID ;

				strcpy(szInst, DropPath(szFile)) ;

				if (ParseBudID(szFile, &ToFro) == IMG) // is loaded, so szFile must in fact exist!
				{
				// find this prefix ID number among those currently on the system.
				for (i = 0 ; i < A.iPfxIDs ; i++)
				{
					if (!_stricmp(ToFro.Prefix, A.szKnownpfx[i]))
					{
						iPfxID = i ;
						break ;
					}
				}

				// find the Instance ID number of the current image, among those
				// known to the current prefix, which are in ascending time order.
				for (i = 0, n = A.iNumImgperpfx[iPfxID] ; i < n ; i++)
				{
					iImID = A.Imgperpfx[iPfxID][i] ;
					if (!_stricmp(szInst, A.szKnownimg[iImID]))
					{
						index = i ;
						break ;
					}
				}

				// if we have not reached the end of the list, i.e., the latest,
				// then we want the instance after the incumbent one
				if (index < (n - 1)) 
				{
					LPSUITE sui ;
					  int pthord ;

					iImgID = A.Imgperpfx[iPfxID][index + 1] ;

						   sui = A.pSuiteperpfx[iPfxID][UseSuite] ;	// use the current suite
					    pthord = sui->iIMGpth ;						// image path from the suite
					   iPathID = A.iPthIDperimg[iImgID][pthord] ;	// the path ID specific to the image

				// form the full path to the image
					strcpy(szFileName, A.szKnownpth[iPathID]) ;	// path string		
					strcat(szFileName, A.szKnownimg[iImgID]) ;	// image file name

				// is it there?
					if ((hUp = OpenFile(szFileName, &of1, OF_EXIST)) != HFILE_ERROR)
					{
						if (toArchive)
						{
						strcpy(szArchFile, szFile) ;	// copy incumbent file's name
						SaveAllAway() ;					// archive incumbent's details
						}

		        // Load the file in the usual fashion.
					strcpy(szFile, szFileName) ;		// make the incoming file name the incumbent
					Sequencing = 1 ;					// flag that we are sequencing
					SendMessage(hWndCtrl, WM_COMMAND, IDM_OPEN_FILE, 0L) ;	// open the file
					Sequencing = 0 ;					// cancel sequencing
					}
					else // we didn't find the file
					{
					  MessageBox(NULL,
						  "Image file not found on the given path",
						  "Forwards Sequencing", MB_OK) ;
					}
				}
				 else // say we've topped out, then just drop through (but save previous anyway)
					{
						if (toArchive)
						{
						strcpy(szArchFile, szFile) ;	// copy incumbent file's name
						SaveAllAway() ;					// archive incumbent's details
						}

						if (batching)
						{
							batching = 0 ;
							SetWindowText(GetDlgItem(hArcDlg, IDC_B_BATCH), "Batch") ;
							goto stopbatch;
						}
						MessageBox(NULL,
							"No later Image files with the given prefix are available.",
							"Forwards Sequencing", MB_OK) ;
stopbatch:;
					}
				}
				else // Image not in the records
					MessageBox(NULL, "Not a validly named Image", "Forwards Sequencing", MB_OK) ;
			}
						break ;

		//======================================================================
		//======================================================================

					case IDM_SET_SEARCH:
						{
							HWND hW ;

							hW = GetDlgItem(hArcDlg,IDC_B_SEARCHSYSTEM) ;				// the Find Items button
							EnableWindow(hW, FALSE) ;									// disable it pro tem

							SetDlgItemText(hArcDlg, IDC_E_SEARCHZONE, "") ;				// clear the tell-tale edit box

							EnableWindow(hW, PidlBrowse(hWndBud, 0, pszDisplayName)) ;		// pick the directory, & enable the Find Items button

							wpps("SearchZone","Default", szSearchDir, "Bud32.bud") ;	// record in Bud32.bud, so the default zone survives the session

							SetWindowText(hW, "FIND ITEMS") ;							// signal that search is available

							SetDlgItemText(hArcDlg, IDC_E_SEARCHZONE, szSearchDir) ;	// fill the tell-tale
								break ;
						}

//***************************************************************************
//  OPEN A BUD FILE I  Direct Open
//***************************************************************************

				case IDM_OPEN_BUD:
						{
							char f[MAX_PATH] ;
							char szFolder[MAX_PATH] ;
						   static BUDID Bud ;
						    HISSRC  hSrc ;
							HISDEST hDest ;
							HGLOBAL hRGB ;
							BYTE * pRGB ;
							UINT32 wid, hyt ;

				if (!searched)
				{
					char str[256] ;
					sprintf(str,
                            "Please Conduct a Search for Bud Files\n" \
                            "before attempting to load an Instance\n" \
                            "into the Bud Workshop.") ;

					MessageBox(NULL, str, "Search Needed", MB_OK) ;
					goto skip_this ;
				}

				 if (GetBudFile(hWndRslt) != TRUE)
				 {
					 char str[256] ;
					sprintf(str, "File not found.") ;

					MessageBox(NULL, str, "No File", MB_OK) ;
					goto nofile ;	// The wanted file isn't there.
				 }

				// otherwise, we have the file
				 if 
				(
					ParseBudID(strcpy(f, szFile), Search_ID) == IMG
				)
				 {
					 Bud = * Search_ID ;
					 strcpy(szFolder, szSearchDir) ;
					 strcat(szFolder, "\\All IMG\\") ;
					 strcat(szFolder, Bud.Prefix) ;
					 strcat(szFolder," default") ;
					if (GetFileAttributes(szFolder) == -1)
					{
					  // the image file folder is not in the Archive
						int r = 0 ;
						r =_mkdir(szFolder) ;
						if (r == 0)
						Note(1,"Making Folder") ;
					}


					// Folder exists in the Archive
					Note(1,"Folder Exists") ;

					// Comstruct full path to the image
					strcat(szFolder,"\\") ;
					strcat(szFolder, DropPath(szFile)) ;

					// is the image file its archive folder?
					if ((hSrc = _ISOpenFileSource(szFolder)) != (HISSRC)NULL)
					{
						// the image file is in its Archive folder

						_ISCloseSource(hSrc) ;
					 UpdatingRecords = Sequencing = skipgetfile = 0 ;
					 SendMessage(hWnd, IDC_B_SEARCHSYSTEM, 0, 0L) ;

					}
					else // no, the image file is not in its archive folder
					{
						// So, load the image from wherever it is now
						if ((hSrc = _ISOpenFileSource(szFile)) != (HISSRC)NULL)
						{
						_ISSeek(hSrc,0,0) ;

						hRGB = _ISReadJPG			// get the image
						(
						hSrc,
						&wid,
						&hyt,
						24
						) ;

						pRGB = (BYTE *) hRGB ;		// we have the image in rgb format
						_ISCloseSource(hSrc) ;		// shut the source

						hDest = _ISOpenFileDest( szFolder ) ;			// szFolder is the fully qualified path of a JPG

						_ISWriteJPG					// write the image to its archive folder
						(
							hDest,
							pRGB,
							wid,
							hyt,
							JPGQuality,
							0,
							24,
							NULL
						) ;

						_ISCloseDest(hDest) ;		// Shut the source
						GlobalFree(hRGB) ;			// free stuff

						// The image is now in its Archive folder

						Note(1, "Image installed.") ;
						UpdatingRecords = Sequencing = skipgetfile = 0 ;
						SendMessage(hWnd, IDC_B_SEARCHSYSTEM, 0, 0L) ;


					  } // if ((hSrc = ...
					UpdatingRecords = Sequencing = skipgetfile = 0 ;
					SendMessage(hWnd, IDC_B_SEARCHSYSTEM, 0, 0L) ;
					} // the image file is not in its archive folder

				 } // if (ParseBud...
skip_this:;
						break;
						}

//***************************************************************************
//  OPEN A BUD FILE II  Indirect Open
//***************************************************************************
                  case IDM_OPEN_FILE:
					  {
						  static HISSRC hSrc ;

				if (!searched)
				{
					char str[256] ;
					sprintf(str,
                            "Please Conduct a Search for Bud Files\n" \
                            "before attempting to load an Instance\n" \
                            "into the Bud Workshop.") ;

					MessageBox(NULL, str, "Search Needed", MB_OK) ;
					goto skip_open ;
				}

    			// reset the results window
			    SendMessage(hWndRslt,WM_RESET,0,0L) ;

				// 14/12/2003 - Another major bugfix: tracking a file left the scanning flag
				// turned on. If a new bud was asked for immediately, then the line scan
				// allocations were wiped, and unavailable, and the uncancelled scan tried to
				// access it, causing a GPF, and a crash.  We deal with this by turning scanning
				// (and graphing) off on _any_ call to open an image file, _before_ it is opened. 

                 // are we showing lines scan graphs? Turn 'em off!
				 if (graphing)
				 SendMessage(hWndBud,WM_COMMAND,TOGGLE_GRAPHS,0L) ;
				// are we scanning? Stop scanning!
				 if (scanning)
				 SendMessage(hWndBud,WM_COMMAND,TOGGLE_SCAN,0L) ;
				

				// Now prepare for the new image.

				if (UpdatingRecords || Sequencing || skipgetfile) goto udate ; // skip user input

          if ( GetBudFile(hWndRslt) == TRUE)
					clips = 0 ;		// We have the file
                else
					goto nofile ;	// The wanted file isn't there.

				// It's there.
				
				// ***  SERIOUS BUGFIX ***
				//  Save all archive stuff away
				// _BEFORE_ attempting to load the image.
				//  This should ensure that the correct
				// (i.e. current)parameters	are used.

udate:			if (toArchive)
				{
				strcpy(szArchFile, szFile) ;
				SaveAllAway() ;
				} // This seems to work OK No it bloody doesn't!!

				if (Select2BW) { strcpy(szFile, szMRUpvu) ; Select2BW = 0 ; } // is a select into BW from the tree

				   clips = 0 ; // initialise sound bites
				  
				// See what it is..

			      hSrc = _ISOpenFileSource( szFile ) ;
                  ftyp = _ISGuessFileType(hSrc) ;
				 _ISSeek(hSrc, 0, 0) ;
				 _ISCloseSource(hSrc) ;

                switch ( ftyp ) // ..and act accordingly.
                {
				case 1:
					         strcpy(string, "BMP image") ; // Is a bitmap.
					 // try to load the bitmap to an RGB Buffer
                             if(
								 !LoadBMformat() // If it doesn't load..
							   )
							 {
                             strcat( string, ", load failed") ;
							 }
							 else
							 {
			// The .BMP loaded, so here we go!
							    PlayList[clips++] = 0 ;
								// go process the incoming instance
								first_bud_ep = 0.0 ;
								final_bud_ep = 1.0e20 ;
								ProcessDIB() ;
							 }
							 break ;

				case 3:
is_jpg:	                    strcpy(string, "JPEG image") ; // is a JPEG
					 // try to load and decompress to an RGB Buffer
							if (
					             !LoadJPformat() // if it doesn't work
							   ) 
							 {
                              strcat( string, ", failed") ;
							 }
							 else
							 {
			// The .JPG loaded, and converted OK, so off we go!
						        PlayList[clips++] = 1 ;
								// go process the incoming instance
								first_bud_ep = 0.0 ;
								final_bud_ep = 1.0e20 ;
						
							    ProcessDIB() ;
							 }
							 break ;

				case 0:		 switch(CheckFileType()) // Guess type has failed, use alternative
							 {
				              case JPtyp: goto is_jpg ;
							  break ;
				              default: break ;
							 }
					         strcpy(string, " Unrecognised or Unsupported type") ;
						     PlayList[clips++] = 10 ;
							 msgbox = 1 ;
							 MessageBox(
								 NULL,
								 "The Bud Workshop\n" \
								 "does not recognise\n" \
								 "the format of this file.",
								 "Unsupported File type",
								 MB_OK
								 ) ;
							 msgbox = 0 ;
						     break ;

				default:    strcpy(string, "Something odd here!") ;
					         break ;
                }

			// Advertise presence
				{
					LPSUITE ps ;
					ps = A.pSuiteperpfx[BudPfxID][UseSuite] ;

				strcpy(szBudWindowTit1, szBudWindowTxt1) ;
				strcat(szBudWindowTit1, " - ") ;
				strcat(szBudWindowTit1, ps->desc) ;
                strcat(szBudWindowTit1, DropPath(szFile)) ;
                strcat(szBudWindowTit1, " - " ) ;
                strcat(szBudWindowTit1, string ) ;
                SetWindowText(hWndBud, szBudWindowTit1) ;

				strcpy(szResWindowTit, szResWindowTxt) ;
				strcat(szResWindowTit, " - ") ;
				strcat(szResWindowTit, ps->desc) ;
                strcat(szResWindowTit, DropExt(DropPath(szFile))) ;
                SetWindowText(hWndRslt, szResWindowTit) ;
				}
skip_open:
				break ;
				}
              } //switch (LOWORD(wParam))
             } //WM_COMMAND
nofile:
        break ;

        case WM_TIMER:

			switch (wParam)
			{

			case IDT_BANNER_TIMER:
		    // Kill the splash screen and its timer.
             DestroyWindow(hWndFlag) ;
             KillTimer(hWndCtrl, IDT_BANNER_TIMER) ;
			 DeleteObject(hFlag) ;
			 banner = 0 ;
			 // Launch from here?
      COL = 1 ;
	while (!SetWindowPos(hWndColl, HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_SHOWWINDOW)) ;
		SendMessage(hWndColl, WM_COMMAND, IDM_ARCHIVIST1, 0L) ;
		UpdateWindow(hArcDlg) ;

	hWndTreeSer = GetDlgItem(hArcDlg, IDC_TREECTL_SER) ;	// get the handle of the per series tree view
	InitTreeViewImageLists(hWndTreeSer) ;					// initialise the per series tree view image list

	hWndTreeExp = GetDlgItem(hArcDlg, IDC_TREECTL_EXP) ;	// get the handle of the "experimental" tree view
	InitTreeViewImageLists(hWndTreeExp) ;					// initialise the "experimental" tree view image list

	hWndTreeArc = GetDlgItem(hArcDlg, IDC_TREECTL_ARC) ;	// get the handle of the Archives tree view
	InitTreeViewImageLists(hWndTreeArc) ;					// initialise the Archives tree view image list

// Find what allowed drives are available on the system.
//	numdrv = FindDrives(hArcDlg) ;
			    break ;

			case IDT_HIT_TIMER:
			{
			static HTREEITEM hti, ohti1, ohti2, ohti3 ;
			TVITEM tvi ;
			  char txt[256] ;
			  HWND hWndPoint ;
			  POINT p ;

			hWndPoint = PickTree( &p ) ;

			if ( hWndPoint == hWndTreeExp )
			{
			tvht1.pt = p ;
			if ((hti = TreeView_HitTest(hWndTreeExp, &tvht1)) != (HTREEITEM)NULL)
			{
				if (hti != ohti1)
				{
					tvi.mask       = TVIF_TEXT;
					tvi.hItem      = hti ;					// give the selection's handle
					tvi.pszText    = txt ;					// text buffer
					tvi.cchTextMax = 256 ;					// length of text buffer
					TreeView_GetItem(hWndTreeExp, &tvi) ;	// go get the item (fills the tvItm struct)
					Note(1, txt) ;							// show, then delete after 1 second
				}
				ohti1 = hti ;
			}
			}

			if ( hWndPoint == hWndTreeSer )
			{
			tvht2.pt = p ;
			if ((hti = TreeView_HitTest(hWndTreeSer, &tvht2)) != (HTREEITEM)NULL)
			{
				if (hti != ohti2)
				{
					tvi.mask = TVIF_TEXT ;
					tvi.hItem = hti ;						// give the selection's handle
					tvi.pszText = txt ;						// text buffer
					tvi.cchTextMax = 256 ;					// length of text buffer
					TreeView_GetItem(hWndTreeSer, &tvi) ;	// go get the item (fills the tvItm struct)
					Note(1, txt) ;							// show, then delete after 1 second
				}
				ohti2 = hti ;
			}
			}

			if ( hWndPoint == hWndTreeArc )
			{
			tvht3.pt = p ;
			if ((hti = TreeView_HitTest(hWndTreeArc, &tvht3)) != (HTREEITEM)NULL)
			{
				if (hti != ohti3)
				{
					tvi.mask = TVIF_TEXT ;
					tvi.hItem = hti ;						// give the selection's handle
					tvi.pszText = txt ;						// text buffer
					tvi.cchTextMax = 256 ;					// length of text buffer
					TreeView_GetItem(hWndTreeArc, &tvi) ;	// go get the item (fills the tvItm struct)
					Note(1, txt) ;							// show, then delete after 1 second
				}
				ohti3 = hti ;
			}
			}
		}
				break ;

			case IDT_GRAB_TIMER:

				GrabFrame() ;

				break ;

			case IDT_DISMISS:
			 ivrc(hWnd, &rctxt, TRUE) ;
             KillTimer(hWnd, IDT_DISMISS) ;
				break ;

		    case IDT_VOCTIMER:

			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseBtn],cupt))
			 {
				PlaySound(szVocTipWav[UseBtn], NULL, SND_ASYNC) ;
			 }
			 KillTimer(hWnd,VTim) ;

			    break ;
		    
			case IDT_TIPDWELL:
			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 DestroyWindow(hWndInfo[UseCtl]) ;
				 CurrentTip = (HWND)NULL ;
				 hWndOfCurrentTip = (HWND)NULL ;
			 }
			 KillTimer(hWnd, IDT_TIPDWELL) ;
			 Dwelling[UseCtl] = 0 ;
				return 0L ;
			
			case IDT_TIPDEFER:

			 KillTimer(hWnd,IDT_TIPDEFER) ;
			 Deferred[UseCtl] = 0 ;

			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;

			 if (PtInRect(&rctl[UseCtl],cupt))
				 switch( UseCtl )
				 {
				  case Xit: PutTip(hWnd, -12,   3) ; break ;
				  case Prv: PutTip(hWnd,   0,   5) ; break ;
				  case Nxt: PutTip(hWnd,   0,   5) ; break ;
				  default:  PutTip(hWnd,   0,   3) ; break ;
				 }

			    break ;

			default:
				break ;
			}
			return 0L ;
        	break ;

		case WM_NCHITTEST: 
	// works for any mouse event in this window

	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

        case WM_MOUSEMOVE:

			pt.x = LOWORD(lParam) ;
			pt.y = HIWORD(lParam) ;

		if (showtips || sounds) // Display tips for the buttons in this window
		{
			GetCursorPos(&cpt) ;	   
			ScreenToClient(hWnd,&cpt) ;
			GetTip(hWnd,Opf,Sla,cpt) ;  // Open File button to Pick Archive button 
			GetTip(hWnd,Xit,Xit,cpt) ;	// Quit button
			GetTip(hWnd,Prv,Svi,cpt) ;	// Next and Previous buttons
	        if (sounds)				   
			{
			GetVoc(hWnd,Opf,Acq,cpt) ;
			GetVoc(hWnd,Xit,Xit,cpt) ;
			}
	    }							   

		break ;

        case WM_LBUTTONDOWN:
			
		pt.x = LOWORD(lParam) ;   // get mouse client coords
		pt.y = HIWORD(lParam) ;   // see if mouse is in a Control

          if (PtInRect(&rctl[Opf],pt))
          {
            Clicked[Opf] = OPF = 1 ;
			KillTip(hWnd, Opf) ;
            ivrc(hWnd,&rctl[Opf],TRUE) ;
          }

          if (PtInRect(&rctl[Prv],pt))
          {
            Clicked[Prv] = PRV = 1 ;
			KillTip(hWnd, Prv) ;
            ivrc(hWnd,&rctl[Prv],TRUE) ;
          }

          if (PtInRect(&rctl[Nxt],pt))
          {
            Clicked[Nxt] = NXT = 1 ;
			KillTip(hWnd, Nxt) ;
            ivrc(hWnd,&rctl[Nxt],TRUE) ;
          }

          if (PtInRect(&rctl[Svi],pt))
          {
            Clicked[Svi] = SVI = 1 ;
			KillTip(hWnd, Svi) ;
            ivrc(hWnd,&rctl[Svi],TRUE) ;
          }

          if (PtInRect(&rctl[Sla],pt))
          {
            Clicked[Sla] = 1 ;
			SLA ^= 1 ;
			KillTip(hWnd, Sla) ;
            ivrc(hWnd,&rctl[Sla],TRUE) ;
			if (SLA) SendMessage(hWnd,WM_COMMAND,IDM_SELECT_SUITE,0L) ;
          }

          if (PtInRect(&rctl[Voc],pt))
          {
            Clicked[Voc] = 1 ;
			KillTip(hWnd, Voc) ;
            VOC ^= 1 ;
			sounds = VOC ;
            ivrc(hWnd,&rctl[Voc],TRUE) ;
          }

           if (PtInRect(&rctl[Cmt],pt))
          {
            Clicked[Cmt] = 1 ;
			KillTip(hWnd, Cmt) ;
            CMT ^= 1 ;
			commentary = CMT ;
            ivrc(hWnd,&rctl[Cmt],TRUE) ;
          }

           if (PtInRect(&rctl[Cap],pt))
          {
            Clicked[Cap] = 1 ;
			KillTip(hWnd, Cap) ;
            CAP ^= 1 ;
            ivrc(hWnd,&rctl[Cap],TRUE) ;
			capture = CAP ; 
          }

           if (PtInRect(&rctl[Tgr],pt))
          {
            Clicked[Tgr] = 1 ;
			KillTip(hWnd, Tgr) ;
			SendMessage(hWndCtrl, WM_COMMAND, IDM_M_GRAB_SETUP, 0L) ; 
          }

           if (PtInRect(&rctl[Gps],pt))
          {
            Clicked[Gps] = 1 ;
			KillTip(hWnd, Gps) ;
			SendMessage(hWndCtrl, WM_COMMAND, IDM_M_GPS, 0L) ; 
          }

         if (PtInRect(&rctl[Xit],pt))
          {
            Clicked[Xit] = 1 ;
			KillTip(hWnd, Xit) ;
            XIT = 1 ;
            ivrc(hWnd,&rctl[Xit],TRUE) ;
          }

          if (PtInRect(&rctl[Col],pt))
          {
            Clicked[Col] = 1 ;
			KillTip(hWnd, Col) ;
            SendMessage(hWnd,WM_COMMAND,IDM_COLLATE_DATA,0L) ;
          }

		  if (PtInRect(&rctl[Acq],pt))
		  {
            Clicked[Acq] = 1 ;
			KillTip(hWnd, Acq) ;
			SendMessage(hWnd,WM_COMMAND,IDM_TWAIN_ACQUIRE,0L) ;
		  }
        break ;

        case WM_LBUTTONUP:
			
			pt.x = LOWORD(lParam) ;   // get mouse client coords
			pt.y = HIWORD(lParam) ;   // see if mouse is in a Control

          if (PtInRect(&rctl[Opf],pt))		//Open an image directly
          {
            OPF = 0 ;
			
            ivrc(hWnd,&rctl[Opf],TRUE) ;
            SendMessage(hWnd, WM_COMMAND, IDM_OPEN_BUD, 0L) ;
			
          }
		            if (PtInRect(&rctl[Prv],pt))
          {
            PRV = 0 ;
            ivrc(hWnd,&rctl[Prv],TRUE) ;
			SendMessage(hWnd,WM_COMMAND,IDM_PREV_FILE,0L) ;
          }

          if (PtInRect(&rctl[Nxt],pt))
          {
            NXT = 0 ;
            ivrc(hWnd,&rctl[Nxt],TRUE) ;
			SendMessage(hWnd,WM_COMMAND,IDM_NEXT_FILE,0L) ;
          }

          if (PtInRect(&rctl[Svi],pt))
          {
            SVI = 0 ;
            ivrc(hWnd,&rctl[Svi],TRUE) ;
						strcpy(szArchFile, szFile) ; // copy incumbent file's name
						SaveAllAway() ;
          }

          if (PtInRect(&rctl[Xit],pt))
          {
            XIT = 0 ;
            ivrc(hWnd,&rctl[Xit],TRUE) ;
            SendMessage(hWnd,WM_COMMAND,IDM_EXIT,0L) ;
          }

        break ;

        case WM_PAINT:
               hdc = BeginPaint(hWnd, &ps) ;
            hmemDC = CreateCompatibleDC(hdc) ;
             GetObject(bmOPF, sizeof(BITMAP), &bm ) ;
	       OBm = SelectObject(hmemDC, bmOPF) ;

	   if( !OPF )
               SelectObject(hmemDC, bmOPF) ;
            else
               SelectObject(hmemDC, bmOPFO) ;

               BitBlt(hdc, rctl[Opf].left,
                           rctl[Opf].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !PRV )
               SelectObject(hmemDC, bmPRV) ;
            else
               SelectObject(hmemDC, bmPRVO) ;

               BitBlt(hdc, rctl[Prv].left,
                           rctl[Prv].top,
                           rctl[Prv].right  - rctl[Prv].left,
                           rctl[Prv].bottom - rctl[Prv].top,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !NXT )
               SelectObject(hmemDC, bmNXT) ;
            else
               SelectObject(hmemDC, bmNXTO) ;

               BitBlt(hdc, rctl[Nxt].left,
                           rctl[Nxt].top,
                           rctl[Nxt].right  - rctl[Nxt].left,
                           rctl[Nxt].bottom - rctl[Nxt].top,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !SVI )
               SelectObject(hmemDC, bmSVI) ;
            else
               SelectObject(hmemDC, bmSVIO) ;

               BitBlt(hdc, rctl[Svi].left,
                           rctl[Svi].top,
                           rctl[Svi].right  - rctl[Svi].left,
                           rctl[Svi].bottom - rctl[Svi].top,
                      hmemDC, 0, 0, SRCCOPY ) ;

           if( !VOC )
               SelectObject(hmemDC, bmVOC) ;
            else
               SelectObject(hmemDC, bmVOCO) ;

               BitBlt(hdc, rctl[Voc].left, 
                           rctl[Voc].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;
           
		   if( !CMT )
               SelectObject(hmemDC, bmCMT) ;
            else
               SelectObject(hmemDC, bmCMTO) ;

               BitBlt(hdc, rctl[Cmt].left, 
                           rctl[Cmt].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

		   if( !ACQ )
		   {
			   if (acquired)
               SelectObject(hmemDC, bmACQD) ;
			   else
               SelectObject(hmemDC, bmACQ) ;
		   }
            else
               SelectObject(hmemDC, bmACQO) ;

               BitBlt(hdc, rctl[Acq].left, 
                           rctl[Acq].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

           if( !CAP )
               SelectObject(hmemDC, bmCAP) ;
            else
               SelectObject(hmemDC, bmCAPO) ;

               BitBlt(hdc, rctl[Cap].left,
                           rctl[Cap].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

           if( !TGR )
               SelectObject(hmemDC, bmTGR) ;
            else
               SelectObject(hmemDC, bmTGRO) ;

               BitBlt(hdc, rctl[Tgr].left,
                           rctl[Tgr].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

           if( !GPS )
               SelectObject(hmemDC, bmGPS) ;
            else
               SelectObject(hmemDC, bmGPSO) ;

               BitBlt(hdc, rctl[Gps].left,
                           rctl[Gps].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

           if( !SLA )
               SelectObject(hmemDC, bmSLA) ;
            else
               SelectObject(hmemDC, bmSLAO) ;

               BitBlt(hdc, rctl[Sla].left,
                           rctl[Sla].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

           if( !XIT )
               SelectObject(hmemDC, bmXIT) ;
            else
               SelectObject(hmemDC, bmXITO) ;

               BitBlt(hdc, rctl[Xit].left,
                           rctl[Xit].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

           if( !COL )
               SelectObject(hmemDC, bmCOL) ;
            else
               SelectObject(hmemDC, bmCOLO) ;

               BitBlt(hdc, rctl[Col].left,
                           rctl[Col].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

			SelectObject(hmemDC,OBm) ;
            DeleteDC(hmemDC) ;
            EndPaint(hWnd, &ps) ;
            return 0 ;
        break ;

        case WM_MOVE:
        case WM_SIZE:
        case WM_WINDOWPOSCHANGED:
        if (scanning) ShowSmoothing(hWndScan) ;
        return 0 ;
        break ;

            case WM_CREATE:

		  hAccel4 = LoadAccelerators(hInst,MAKEINTRESOURCE(IDR_ACCELERATOR4)) ;

       //Bitmap Controls

            bmOPF = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_OPEN_BUD)) ;
           bmOPFO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_OPEN_BUD_ON)) ;
            bmVOC = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BLURB)) ;            
           bmVOCO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BLURB_ON)) ;            
            bmCMT = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_COMMENTARY)) ;            
           bmCMTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_COMMENTARY_ON)) ;            
            bmXIT = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_EXIT)) ;            
           bmXITO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_EXIT_ON)) ;            
            bmCOL = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_COL)) ;            
           bmCOLO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_COL_ON)) ;            
            bmACQ = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ACQUIRE_IMAGE)) ;            
           bmACQO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ACQUIRE_IMAGE_ON)) ;            
           bmACQD = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ACQUIRED)) ;
		   
           bmNXT  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NEXT_FILE)) ;            
           bmNXTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NEXT_FILE_ON)) ;            
           bmPRV  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PREV_FILE)) ;            
           bmPRVO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PREV_FILE_ON)) ;
           bmCAP  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CAPTURE)) ;            
           bmCAPO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CAPTURE_ON)) ;
           bmTGR  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_TIMEDGRAB)) ;            
           bmTGRO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_TIMEDGRAB_ON)) ;
           bmSLA  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_ARCHIVE)) ;            
           bmSLAO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_ARCHIVE_ON)) ;
           bmSVI  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SAVE_INST)) ;
           bmSVIO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SAVE_INST_ON)) ;
           bmGPS  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GPS)) ;
           bmGPSO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GPS_ON)) ;

		 hDefault = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PREVIEWDEFAULT)) ;

		   hDlgCaptDriver = CreateDialog(
			   hInst,
			   MAKEINTRESOURCE(IDD_SELCAPTDRIVER),
			   hWndCtrl,
			   SelCaptDriverDlg) ;

		   hDlgCaptDriver_List = GetDlgItem(hDlgCaptDriver,IDC_CAPDRIVERLIST) ;

		   EnumCapDrv() ;

		   hDlgGPS = CreateDialog(
			   hInst,
			   MAKEINTRESOURCE(IDD_GPS_CONFIG),
			   hWndCtrl,
			   GPSDlgProc) ;

              return 0L ;
            break ;

// This window is the last to be destroyed: remove everything else that
// needs to go before calling quits. Leave no loose ends!

		case WM_DESTROY:

			   //button bitmap resources
               DeleteObject(bmOPF) ;
               DeleteObject(bmOPFO) ;          
               DeleteObject(bmVOC) ;
               DeleteObject(bmVOCO) ;          
               DeleteObject(bmCMT) ;
               DeleteObject(bmCMTO) ;          
               DeleteObject(bmXIT) ;
               DeleteObject(bmXITO) ;
               DeleteObject(bmCOL) ;
               DeleteObject(bmCOLO) ;
               DeleteObject(bmACQ) ;
               DeleteObject(bmACQO) ;
               DeleteObject(bmACQD) ;

               DeleteObject(bmNXT) ;
               DeleteObject(bmNXTO) ;
               DeleteObject(bmPRV) ;
               DeleteObject(bmPRVO) ;
               DeleteObject(bmCAP) ;
               DeleteObject(bmCAPO) ;
               DeleteObject(bmTGR) ;
               DeleteObject(bmTGRO) ;
               DeleteObject(bmSLA) ;
               DeleteObject(bmSLAO) ;
               DeleteObject(bmSVI) ;
               DeleteObject(bmSVIO) ;
               DeleteObject(bmGPS) ;
               DeleteObject(bmGPSO) ;

			   if (hGPSCom)				// this is the GPS COM port (possibly via USB)
			   CloseHandle(hGPSCom) ;

			   if (hDefault)
			   DeleteObject(hDefault) ;
			   if (hPreview)
			   DeleteObject(hPreview) ;

			   if (hPatch)
			   DeleteObject(hPatch) ;
			   if (hPatch1)
			   DeleteObject(hPatch1) ;
			   if (hPatch2)
			   DeleteObject(hPatch2) ;
			   if (hPatch3)
			   DeleteObject(hPatch3) ;

			   // fonts, pens and brushes
               DeleteObject(hfnt ) ;
               DeleteObject(hfnt1) ;
               DeleteObject(hfnt2) ;
			   DeleteObject(hfnt4) ;
               DeleteObject(hgrk ) ;
               DeleteObject(hgrk1) ;
               DeleteObject(hgrk2) ;
			   DeleteObject(hgrk4) ;
               DeleteObject(    bluePen ) ;
               DeleteObject(  ltbluePen ) ;
               DeleteObject(  plbluePen ) ;
               DeleteObject(  dkbluePen ) ;
               DeleteObject(   whitePen ) ;
               DeleteObject(   greenPen ) ;
               DeleteObject( dkgreenPen ) ;
			   DeleteObject( ltgreenPen ) ;
               DeleteObject( dkgndotPen ) ;
               DeleteObject(  purplePen ) ;
               DeleteObject(     redPen ) ;
               DeleteObject(   ltredPen ) ;
               DeleteObject(   blackPen ) ;
               DeleteObject(  yellowPen ) ;
               DeleteObject(    goldPen ) ;
               DeleteObject(  dkgoldPen ) ;
               DeleteObject( notgoldPen ) ;
               DeleteObject(    grayPen ) ;
               DeleteObject(    palePen ) ;
			   DeleteObject(  blackWPen ) ;
			   DeleteObject(   hOvBrush ) ;

			   DeleteObject(   cbluePen ) ;
			   DeleteObject( cltbluePen ) ;
			   DeleteObject( cplbluePen ) ;
			   DeleteObject( cdkbluePen ) ;
			   DeleteObject(    credPen ) ;
			   DeleteObject(  cdkredPen ) ;
			   DeleteObject(  cltredPen ) ;
			   DeleteObject( cpurplePen ) ;
			   DeleteObject(   ccyanPen ) ;
			   DeleteObject(  cwhitePen ) ;
			   DeleteObject(  cgreenPen ) ;
			   DeleteObject(cdkgreenPen ) ;
			   DeleteObject(cltgreenPen ) ;
			   DeleteObject(  cblackPen ) ;
			   DeleteObject( cyellowPen ) ;
			   DeleteObject( cdkgoldPen ) ;
			   DeleteObject(   cgrayPen ) ;
			   DeleteObject( cdkgrayPen ) ;
			   DeleteObject(   cpalePen ) ;

			   // These are windows. Is need to destroy them?
			   // Well, no harm in it.
			   /****

			   if ( hDlgSource     != NULL) DestroyWindow(hDlgSource) ;
			   if ( hDlgDisplay    != NULL) DestroyWindow(hDlgDisplay) ;
			   if ( hDlgSystemic   != NULL) DestroyWindow(hDlgSystemic) ;
			   if ( hDlgFourier    != NULL) DestroyWindow(hDlgFourier) ;
			   if ( hDlgTuned      != NULL) DestroyWindow(hDlgTuned) ;
			   if ( hDlgSpectra    != NULL) DestroyWindow(hDlgSpectra) ;
			   if ( hDlgSystemicII != NULL) DestroyWindow(hDlgSystemicII) ;
			   if ( hDlgViewSet    != NULL) DestroyWindow(hDlgViewSet) ;
			   if ( hDlgGrabSetUp  != NULL) DestroyWindow(hDlgGrabSetUp) ;
				***/
			   // structs, arrays, buffers etc
               if ( GlobalSize(hResults)) GlobalFree( hResults ) ;
               if ( GlobalSize(hMeasure)) GlobalFree( hMeasure ) ;
			   if ( GlobalSize(hRGB))     GlobalFree( hRGB ) ;
			   if ( GlobalSize(hGRY))     GlobalFree( hGRY ) ;
			   if ( GlobalSize(hSTA))     GlobalFree( hSTA ) ;
			   if ( GlobalSize(pFourier)) GlobalFree( pFourier ) ;
			   if ( GlobalSize(pAlFou))   GlobalFree( pAlFou  ) ;
			   if ( GlobalSize(pFAlFou))  GlobalFree( pFAlFou ) ;
			   if ( GlobalSize(pIMFou))   GlobalFree( pIMFou  ) ;


			   if ( hDib      != NULL) DiscardImage() ;
			   for ( i = 0 ; i < MAXBUDS ; i++ )
			   {
			   if ( GlobalSize(szBudItems[i])) GlobalFree( szBudItems[i] ) ;
			   }
			   for ( i = 0 ; i < 200 ; i++ )
			   {
				   GlobalFree( DimenCombo[i]) ;
				   GlobalFree(ResultCombo[i]) ;
			   }
			   for ( i = 0 ; i < MAXDEPTH ; i++ )
			   {
				   int j ;
				   for ( j = 0 ; j < MAXDIRSATDEPTH ; j++ )
				   {
					if (GlobalSize(szDirpath[i][j])) GlobalFree(szDirpath[i][j]) ;
				   }
			   }
               for ( i = 0 ; i < Planets ; i++ )
			   if (GlobalSize(elvar[i]))
				   GlobalFree( elvar[i] ) ;
			   for ( i = 0 ; i < MAXALS ; i++ )
			   {
				   int j ;
				   for (j = 0 ; j < Planets ; j++)
				   {
			   if (GlobalSize(    Date_Time[j][i]))
				   GlobalFree(    Date_Time[j][i] ) ;
			   if (GlobalSize( modDate_Time[j][i]))
				   GlobalFree( modDate_Time[j][i] ) ;
				   }
			   }
			   if ( GlobalSize(align))  GlobalFree( align ) ;
			   if ( GlobalSize(newbuf)) GlobalFree( newbuf ) ;
			   //if (hWndInfo[NUMCONTROLS] != NULL) DestroyWindow(hWndInfo[NUMCONTROLS]) ;

			   ResetScan() ; // has the effect of freeing all pertaining allocations
			   DestroyWindow(hDlgCaptDriver) ;
               PostQuitMessage(0) ;
			   return 0L ;
            break ;
        	
        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
    }// switch(message)

    return ((long)NULL);
}

int TestTransit( double oldang, double newang, int toRange ) 
{
	double D, sum ;
/*
 * This function accepts an "old" and a "new" angle, both in the full
 * 0 to twopi range, finds the difference between them, and adds that
 * difference to the old angle. If this sum exceeds twopi, the function
 * returns 1.  If this sum falls below zero, the function returns 2.
 * If the incoming angle is to be "ranged" for display -- constrained
 * to lie in the range 0 to pi radians -- then transitions of pi in
 * either sense need noting. The function returns 3 for an upwards
 * transition, and 4 for a downwards transition, of pi.
 *
 * In all cases, a non-zero return-value signals an
 * imminent full-chart transition. 
 */

	     D = adiff(newang, oldang) ;
	   sum = oldang + D ;

			 // about to reach or rise above twopi
		 if ( sum >= twopi ) return 1 ;

			 // about to reach or fall below zero
		 if ( sum <= 0.0)    return 2 ;

			 // if angle is to be ranged (but
		     // is not yet ranged), then we 
		     // also need transitions, in
		     // either sense, of pi.

		 if (toRange)
		 {
		 if (oldang < pi && sum >= pi)  return 3 ;
		 if (oldang > pi && sum <= pi)  return 4 ;
		 }

			return 0 ;  // there was no transition of any type
}

int LineCursor	 // bit of a hack, this!
(
HWND hWnd,
int hits,
int * wasin,
int * activated,
 RECT D,
POINT mouse
)
{
	static  HDC hDC ;
	static HPEN oPen ;
	static oxp, oyp ;

	if (PtInRect(&D, mouse))				// if cursor is in plotting area 
		{
		 hDC = GetDC(hWnd) ;
		oPen = SelectObject(hDC, notgoldPen) ;
		// 'notgold' is a light blue
		// i.e. the complement of gold.
		// It shows as gold when inverted
		// on white. Set this pen to do this.
	    SetROP2(hDC, R2_XORPEN) ;

		if (IsPlotTime) mouseEp = xp2ep(mouse.x) ; // get the epoch at the cursor

		if (* wasin) // is still in:   
		{
		  if (! * activated) // redraw old first to remove cursor if not just activated
		  {
			MoveToEx(hDC, D.left  - 10,  oyp,   NULL) ;
			  LineTo(hDC, D.right + 24,  oyp) ;
			MoveToEx(hDC, oxp,  D.bottom + 30 , NULL) ;
			  LineTo(hDC, oxp,  D.top    - 10) ;
		  }
		  if (hits) // if cursor is in any target rectangle, we hide the cursor
			{
			SetROP2(hDC, R2_COPYPEN) ;
			SelectObject(hDC, oPen) ;
			ReleaseDC(hWnd, hDC) ;
			  return 1 ;		// should stay hidden until toHide is re-set
			}
		}
		else 
		* wasin = 1 ; // just arrived :
		
		if (!hits) // if there are no hits, draw new only
		{
		MoveToEx(hDC, D.left  - 10, mouse.y,   NULL) ; // horizontal arm
		  LineTo(hDC, D.right + 24, mouse.y) ;
		MoveToEx(hDC, mouse.x,  D.bottom + 30, NULL) ; // vertical arm
		  LineTo(hDC, mouse.x,  D.top    - 10) ;
		}
		// in any event, record as old		  
		  oxp = mouse.x ;
		  oyp = mouse.y ;

	    SetROP2(hDC, R2_COPYPEN) ;
		SelectObject(hDC, oPen) ;
		ReleaseDC(hWnd, hDC) ;
	}
	else // is not in now
	{
		if ( * wasin)		// just left
		{
		 hDC = GetDC(hWnd) ;
		oPen = SelectObject(hDC, notgoldPen) ;
	    SetROP2(hDC, R2_XORPEN) ;

			* wasin = 0 ;
			
		// Redraw old only, to get rid of it
		  MoveToEx(hDC, D.left  - 10,  oyp,  NULL) ;
		    LineTo(hDC, D.right + 24,  oyp) ;
		  MoveToEx(hDC, oxp,  D.bottom + 30, NULL) ;
		    LineTo(hDC, oxp,  D.top    - 10) ;

	    SetROP2(hDC, R2_COPYPEN) ;
		SelectObject(hDC, oPen) ;
		ReleaseDC(hWnd, hDC) ;
		}
	}
	return 1 ;
}

int GetPlotMode( void )
{
  if (// we are plotting features versus order: i.e., In the frequency domain 
	  PowerSpectrum || mPowerSpectrum || AmpliSpectrum || mAmpliSpectrum ||
	      PlotPhase || mPlotPhase     || PlotAlPow     || PlotAlAmp      || 
		  PlotAlPha	|| Plot3MLines
     )
	 {
		SetFouFlags2() ;
		 IsPlotOrder = 1 ; // we are plotting something against order
		  IsPlotTime = 0 ; // we are NOT plotting something against time
	    return 0 ;
	 }

	if (// we are plotting features versus time: i.e., In the time domain
			PlotData ||	mPlotData            || PlotSynth          || mPlotSynth       || PlotFSynth       ||
		 mPlotFSynth ||	PlotFAlSynth         || PlotComp           || mPlotComp        || PlotShifts       ||
	     mPlotShifts || PlotMot              || PlotAMot           || PlotNEcLo        ||
		   PlotNEqLo || PlotPeriLo           || PlotBSysAlign    ||
		 PlotSysPeri || PlotSelLong          ||
   PlotMassDirreSun  || PlotAlFrequ          || PlotSysDirOnSun    ||
		  PlotAlData || PlotCRate            || PlotCsqRate        || PlotSysAV        || PlotAlSysAV      ||
   PlotHSysMeanAlign || LPlotSynTune         || mLPlotSynTune      || PlotDirMean      ||
		PlothMassDir || PlotMBDirreSun       || PlotMassDirreSun   ||
	  PlotSysAlOnSun || PlotVectorSum        || PlotVectorDir      || PlotAccelSum     || PlotAccelDir     ||
  PlotObsShift       || PlotAligns           || PlotAllAls         ||
         RastRawDips || RastMeanDips         || RastRawPeaks       || RastMeanPeaks    || RastTunedRawDips ||
   RastTunedMeanDips || RastTunedRawPeaks    || RastTunedMeanPeaks
	   )
	   {
		 SetTimeFlags2() ;
		  IsPlotTime = 1 ; // we are plotting something against time
		 IsPlotOrder = 0 ; // we are NOT plotting something against order
		 return 1 ;
	   }

  if (// we are plotting some form of Agraph
  	PlotAgraph || mPlotAgraph || LPlotSynAgr || mLPlotSynAgr
	 )
	 {
		SetAgrFlags2() ;
		IsPlotOrder = IsPlotTime = 0 ;
		return 2 ;
	 }

  return -1 ;
}

//--------------------------------------------------------------------------------------------------
// The idea with these functions is to write once to show the trace, then write again to remove it.
// This is to avoid refreshing the entire display on every plot/replot---and to get free of WM_PAINT.
//--------------------------------------------------------------------------------------------------

	void PlotSynthRawLambdaSeries()  // the plot is "self-contained"
		{
				static i, go,  xp, yp ;
				static oxp, oyp ;
				double interval, D ;
				  HPEN oPen ;
				  HDC hdc ;
				  hdc = GetDC(hWndArch) ;

				  oPen = SelectObject(hdc, redPen) ;
				     D = HiGH - LoW ;

				 interval = BudGP / (double)(4 * samples - 1) ;

			for ( i = 1, go = 0 ; i <= 4 * samples - 1 ; i++ )
		  {
				xp = ep2xp(i * interval + BudEp1) ;

			if (xp >= xlmar && xp < (xlmar + chartwid))
			{
				yp = rcArc.bottom -
					(int)((double)charthyt * (pSamp->sdata[i-1] - LoW) / D + (double)ylmar) ;

			if (go == 0)
				{oxp = xp, oyp = yp; ++go ;}
			else
				{
				MoveToEx(hdc, oxp, oyp, NULL) ;
				LineTo(hdc, xp, yp) ;
				oxp = xp ; oyp = yp ;
				}
			}
		   }

				SelectObject(hdc, oPen) ;
				ReleaseDC(hWndArch, hdc) ;
		}

//--------------------------------------------------------------------------------------------

	void PlotSynthMeanLambdaSeries()
			{
				static i, go,  xp, yp ;
				static oxp, oyp ;
				double interval, D ;
				  HPEN oPen ;
				  HDC hdc ;
				  hdc = GetDC(hWndArch) ;

				  oPen = SelectObject(hdc, bluePen) ;
				     D = HiGH - LoW ;

				 interval = BudGP / (double)(4 * samples - 1) ;

			for ( i = 1, go = 0 ; i < 4 * samples - 1 ; i++ )
		  {
				xp = ep2xp(i * interval + BudEp1) ;

			if (xp >= xlmar && xp < (xlmar + chartwid))
			{
				yp = rcArc.bottom -
					(int)((double)charthyt * (pSamp->msdata[i-1] - LoW) / D + (double)ylmar) ;

			if (go == 0)
				{oxp = xp, oyp = yp ; ++go ;}
			else
				{
				MoveToEx(hdc, oxp, oyp, NULL) ;
				  LineTo(hdc, xp, yp) ;
				oxp = xp ; oyp = yp ;
				}
			}
		   }
				SelectObject(hdc, oPen) ;
				ReleaseDC(hWndArch, hdc) ;
		}

//-----------------------------------------------------------------------------------------------

	void PlotForcedSynthRawLambdaSeries( void )
			{
				static i, s, go,  xp, yp ;
				static oxp, oyp ;
				double interval, D ;
				  HPEN oPen ;
				  HDC hdc ;
				  hdc = GetDC(hWndArch) ;

				  oPen = SelectObject(hdc, redPen) ;
				     D = HiGH - LoW ;

				 interval = BudGP / (double)(4 * samples - 1) ;

			for ( i = 1, go = 0 ; i <= 4 * samples - 1 ; i++ )
		  {
				xp = ep2xp(i * interval + BudEp1) ;

			if (xp >= xlmar && xp < (xlmar + chartwid))
			{
				yp = rcArc.bottom -
					(int)((double)charthyt * (pSamp->fsdata[i-1] - LoW) / D + (double)ylmar) ;

			if (go == 0)
				{oxp = xp; oyp = yp ; ++go ;}
			else
				{
				MoveToEx(hdc, oxp, oyp, NULL) ;
				LineTo(hdc, oxp = xp, oyp = yp) ;
				}
			}
		   }

				SelectObject(hdc, oPen) ;
				ReleaseDC(hWndArch, hdc) ;
			}

//----------------------------------------------------------------------------

		void PlotForcedSynthMeanLambdaSeries( void )
			{
				static i, s, go,  xp, yp ;
				static oxp, oyp ;
				double interval, D ;
				  HPEN oPen ;
				  HDC hdc ;
				  hdc = GetDC(hWndArch) ;

				  oPen = SelectObject(hdc, bluePen) ;

				     D = HiGH - LoW ;

				 interval = BudGP / (double)(4 * samples - 1) ;

			for ( i = 1, go = 0 ; i <= 4 * samples - 1 ; i++ )
		  {
				xp = ep2xp(i * interval + BudEp1) ;

			if (xp >= xlmar && xp < (xlmar + chartwid))
			{
				yp = rcArc.bottom -
					(int)((double)charthyt * (pSamp->fmsdata[i-1] - LoW) / D + (double)ylmar) ;

			if (go == 0)
				{oxp = xp; oyp = yp ; ++go ;}
			else
				{
				MoveToEx(hdc, oxp, oyp, NULL) ;
				LineTo(hdc, oxp = xp, oyp = yp) ;
				}
			}
		   }
				SelectObject(hdc, oPen) ;
				ReleaseDC(hWndArch, hdc) ;
			}

//---------------------------------------------------------------------------------------

		void PlotTunedSynthRawLambdaSeries( void )
			{
				static i, s, go,  xp, yp ;
				static oxp, oyp ;
				double interval, D ;
				  HPEN oPen ;
				  HDC hdc ;
				  hdc = GetDC(hWndArch) ;

				  oPen = SelectObject(hdc, redPen) ;

				     D = HiGH - LoW ;

				 interval = BudGP / (double)(4 * samples - 1) ;

			for ( i = 1, go = 0 ; i <= 4 * samples - 1 ; i++ )
		  {
				xp = ep2xp(i * interval + BudEp1) ;

			if (xp >= xlmar && xp < (xlmar + chartwid))
			{
				yp = rcArc.bottom -
					(int)((double)charthyt * (pSamp->tsdata[i-1] - LoW) / D + (double)ylmar) ;

			if (go == 0)
				{oxp = xp; oyp = yp ; ++go ;}
			else
				{
				MoveToEx(hdc, oxp, oyp, NULL) ;
				LineTo(hdc, oxp = xp, oyp = yp) ;
				}
			}
		   }
				SelectObject(hdc, oPen) ;
				ReleaseDC(hWndArch, hdc) ;
			}

//----------------------------------------------------------------------------------------------------

		void PlotTunedSynthMeanLambdaSeries( void )
		{
				static i, go,  xp, yp ;
				static oxp, oyp ;
				double interval, D ;
				  HPEN oPen ;
				  HDC hdc ;
				  hdc = GetDC(hWndArch) ;

				  oPen = SelectObject(hdc, bluePen) ;

				     D = HiGH - LoW ;

				 interval = BudGP / (double)(4 * samples - 1) ;

			for ( i = 1, go = 0 ; i <= 4 * samples - 1 ; i++ )
		  {
				xp = ep2xp(i * interval + BudEp1) ;

			if (xp >= xlmar && xp < (xlmar + chartwid))
			{
				yp = rcArc.bottom -
					(int)((double)charthyt * (pSamp->tmsdata[i-1] - LoW) / D + (double)ylmar) ;

			if (go == 0)
				{oxp = xp; oyp = yp ; ++go ;}
			else
				{
				MoveToEx(hdc, oxp, oyp, NULL) ;
				LineTo(hdc, oxp = xp, oyp = yp) ;
				}
			}
		   }
				SelectObject(hdc, oPen) ;
				ReleaseDC(hWndArch, hdc) ;
		}

//-------------------------------------------------------------------------------------------------------

	void PlotRawLambdaSeries(void)
		 {
			static i, go, xp, yp ;
			static oxp, oyp ;
			double D, BudEp ;
			   HDC hdc;
			  HPEN oPen ;
		 LPFOURIER pf ;

			hdc = GetDC(hWndArch) ;
			 pf = pFourier ;
			oPen = SelectObject(hdc, redPen) ;
			D = HiGH - LoW ;
			for (i = 1, go = 0 ; i <= A.iNumImgperpfx[CurrentPfxID] ; i++)
			{
				BudEp = A.fEpperpfx[CurrentPfxID][i - 1] ;
						xp = ep2xp(BudEp) ;
					if (xp >= xlmar && xp < (xlmar + chartwid))
					{
						yp = rcArc.bottom -
							(int)((double)charthyt *
									(pf->data[i-1] - LoW) / D + (double)ylmar) ;
									if (go == 0)
									{oxp = xp ; oyp = yp ; ++go ;}
									else
									{
										MoveToEx(hdc, oxp, oyp, NULL) ;
										LineTo(hdc, oxp = xp, oyp = yp) ;
									}
					}
			}
				SelectObject(hdc, oPen) ;
				ReleaseDC(hWndArch, hdc) ;
		 }

//----------------------------------------------------------------------------------------------------

	void PlotMeanLambdaSeries(void)
		 {
			static i, go, xp, yp ;
			static oxp, oyp ;
			double D, BudEp ;
			   HDC hdc;
			  HPEN oPen ;
		 LPFOURIER pf ;

			hdc = GetDC(hWndArch) ;
			 pf = pFourier ;
			oPen = SelectObject(hdc, bluePen) ;
			D = HiGH - LoW ;
			for (i = 1, go = 0 ; i <= A.iNumImgperpfx[CurrentPfxID] ; i++)
			{
				BudEp = A.fEpperpfx[CurrentPfxID][i - 1] ;
						xp = ep2xp(BudEp) ;
					if (xp >= xlmar && xp < (xlmar + chartwid))
					{
						yp = rcArc.bottom -
							(int)((double)charthyt *
									(pf->mdata[i-1] - LoW) / D + (double)ylmar) ;
									if (go == 0)
									{oxp = xp ; oyp = yp ; ++go ;}
									else
									{
										MoveToEx(hdc, oxp, oyp, NULL) ;
										LineTo(hdc, oxp = xp, oyp = yp) ;
									}
					}
			}
				SelectObject(hdc, oPen) ;
				ReleaseDC(hWndArch, hdc) ;
		 }
//------------------------------------------------------------------------------------------------
	void PlotSynthRawDips( void )
	{
  			static i, Y, xp, yp ;
			double sh, g, D ;
			HPEN oPen ;
			HDC hdc ;

				hdc = GetDC(hWndArch) ;
				D = HiGH - LoW ;

			for (i = 0 ; i <= pSamp->nDips ; i++)
			{
				xp = ep2xp(g = pSamp->DipEps[i]) ;

				if (xp >= xlmar && xp <= (xlmar + chartwid))
				{
				yp = rcArc.bottom - 
						((int)((double)charthyt * (pSamp->DipVal[i] - LoW) / D)  +  ylmar) ;

				DrawIcon(hdc, xp - 15, yp - 31, icDipRaw) ;	// draw the icon

				SetRect(&rcRawDip[i], xp - 5, yp - 5, xp + 5, yp + 5) ; // rectangle for mousing

				if (ShowShifts)	// vertically
					{
						oPen = SelectObject(hdc, redPen) ;
						  sh = pSamp->rdpShift[i] ;
						   Y = rcArc.bottom - ((int)((double)charthyt * (1.0 - fabs(sh)/14.0)) + ylmar) ;

						Ellipse(hdc, xp - 5, Y - 5, xp + 5, Y + 5 ) ;

						DrawCross(hWndArch, 0, xp, Y, 6, redPen) ;
						SelectObject(hdc, oPen) ;

						if (toLink)
						{
							oPen = SelectObject(hdc, ltredPen) ;
							MoveToEx(hdc,xp, yp, NULL) ;
							LineTo(hdc, xp, Y) ;
							SelectObject(hdc, oPen) ;

						} // End if (toLink)
					} // End if (ShowShifts)
				} // End if (xp >= ...
			} // End for (i = 0 ...

			ReleaseDC(hWndArch,hdc) ;

	} // End PlotSynthRawDips()

// **************************************************************
//             Archive Operations Window (Ver 2)
// **************************************************************
long CALLBACK ArchiveWorkProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps ;
static     SIZE sz ;
static      HDC hdc, hmemDC, hDC ;
static 	HBITMAP bitmap, modbitmap, oBm ;
static  HBITMAP bmAlig,   bmVenus,   bmMars,   bmJupiter, bmSun ;
static  HBITMAP bmSaturn, bmMercury, bmUranus, bmNeptune, bmMEP ;
static  HBITMAP bmphVenus,   bmphMars,   bmphJupiter, bmphSun ;
static  HBITMAP bmphSaturn, bmphMercury, bmphUranus, bmphNeptune ;
static     HPEN oPen ;
static	  HFONT oFnt ;
static   HBRUSH oBsh ;
static	  POINT mouse, mse, cpt, cupt, box, pt ;
static     HWND hActiveWnd ;

		 //static xlmar = 40, xrmar = 40, ylmar = 40, yhmar = 65 ;
		 static Xlmar, Xrmar = 10 ;
		 static oldx ;

		 static wd, Wd, ht, big, is_al, transit, first_al_to_show = 0 ;
static     RECT D, H, S1, S2, S3, rctxtblock1, rctxtblock2, rcDlg ;
static     RECT rcalig[MAXALS], rcinter_al[MAXALS] ;
static     RECT rcmodalig[MAXALS], rcmodinter_al[MAXALS] ;
		 static i, j, k, m, n, xp, yp, oxp, oyp, index1, k_index ;
		 static wasin = 0, wasactive = 0, activated = 0 ;
		 static UseScale = 1, on_plot = 0 ;
static   double hi_y, lo_y, u, ymul ;
static   sh ;
static   double Dcnt, ang, rSum, mSum ;
static   double oldang, newang ; 
static   double th, ys, coe, Am, Ph, Dm, major, minor ;
		 //double prd ;
static   double Lowdays, Highdays, Highfrq, Lowfrq ;
		 static FOS = 0 ;
static     char buff[80], buffer[100] ;
  // Agraph stuff
static	 double rTotal[17], mTotal[17], rItems[17], mItems[17] ;
static   double * rData[17], * rd ;
static   double * mData[17], * md ;
static   double rStdDev[17], mStdDev[17] ;
static   double epDat, epData, epAl ;
static	 double rhiAg, rloAg, rhi_Y, rlo_Y ;
static   double mhiAg, mloAg, mhi_Y, mlo_Y ;
static   double chi_Y, clo_Y ;
	     static prevday, alignday[100], DAY, DAYS, PREDAYS, DY, rLODAY, mLODAY ;

static	 double lo_f ;	//  lowest scale order
static   double hi_f ;	// highest scale order
static	 double fspan ;	// order span of _scale_ (i.e., not actual span)
static	 double    os ; // order step
static	 double    or ; // order


    switch (message)
    {
	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
	   case WM_MOUSEGONE:
	    // the rodent has just left this window.
		   if (CurrentTip != NULL)
		   RemoveTip() ;
		   break ;

	   case IDM_SHOW_SETUP:

			FOS ^= 1 ;
		ivrc(hWnd,&rctl[Fos],FALSE) ;

		if (FOS)
		{
		 if (hPanelDlg == (HWND)NULL)	  // if not yet created, create it now
           hPanelDlg = CreateDialog
			          (
			            hInst,
			           "IDD_CONTROL_PANEL",
			            hWndCtrl,
			            CtlPanelDlgProc
			          ) ;

			ShowWindow(hPanelDlg, SW_SHOW) ;	// show the control panel
				SetWindowPos(hPanelDlg, HWND_TOP,
					         0,0,0,0,
							 SWP_NOSIZE|SWP_NOMOVE) ;

				GetWindowRect(hPanelDlg,&rcDlg) ; // to reposition the archive window

			FouSetUp = 1 ;
		}
		else
		{
		   SendMessage(hPanelDlg, CLOSEALL, 0, 0L) ; // close ancillary window(s)
			ShowWindow(hPanelDlg, SW_HIDE) ;		   // hide control panel
			FouSetUp = 0 ;
		}
		   break ;

	//  --- cross referencing from the raster view ---
	// when the cursor points to an event on the raster, a 
	// rectangle appears enclosing the same event on the chart.

	  case WM_XREF:
		  {
			   int a, xp, yp ;
			double u, v ;

			 a = LOWORD(lParam) ; // item index

			 switch (HIWORD(lParam)) // item type
			 {
			 case URDP: u =    Samp.DipEps[a] ; v =    Samp.DipVal[a] ; break ;
			 case TRDP: u =   Samp.tDipEps[a] ; v =   Samp.tDipVal[a] ; break ;
			 case UMDP: u =   Samp.mDipEps[a] ; v =   Samp.mDipVal[a] ; break ;
			 case TMDP: u =  Samp.tmDipEps[a] ; v =  Samp.tmDipVal[a] ; break ;

			 case URPK: u =   Samp.PeakEps[a] ; v =   Samp.PeakVal[a] ; break ;
			 case TRPK: u =  Samp.tPeakEps[a] ; v =  Samp.tPeakVal[a] ; break ;
			 case UMPK: u =  Samp.mPeakEps[a] ; v =  Samp.mPeakVal[a] ; break ;
			 case TMPK: u = Samp.tmPeakEps[a] ; v = Samp.tmPeakVal[a] ; break ;
			 case   AL:	u =     Als.Alepof[a];	v = hi_y ;				break ;
			 //case MAL:	break ;
			 }

				xp = ep2xp(u) ;
				yp = rcArc.bottom -	((int)((double)ht * (v - lo_y) / (hi_y - lo_y))  +  ylmar) ;

			 switch (HIWORD(lParam)) // item type
			 {
				// rect on dip
			 case URDP: 
			 case TRDP: 
			 case UMDP: 
			 case TMDP: DrawRect(hWnd, 1, xp - 7, yp - 22, xp + 7, yp + 5, whitePen) ;  break ;
				// rect on peak
			 case URPK:
			 case TRPK:
			 case UMPK:
			 case TMPK: DrawRect(hWnd, 1, xp - 7, yp - 5, xp + 7, yp + 22, whitePen) ; break ;

			 case AL:	 // rect on alignment icon
						DrawRect(hWnd, 1, xp - 7, yp + 2, xp + 7, yp + 30, yellowPen) ;
						// rect on alignment marker
						yp = rcArc.bottom - ((int)((double)ht * range(Als.Alongof[a]) / pi) + ylmar) ;
						DrawRect(hWnd, 1, xp - 5, yp - 5, xp + 5, yp + 5,  yellowPen) ; break ;
			 }
		  }
		  break ;

		default: break ;
		} // end of switch(LOWORD(wParam))
		return 0L ; // for case WM_COMMAND

	  case WM_MOVE:
	  case WM_SIZE:
	  case WM_WINDOWPOSCHANGED:
		  updisp() ;
		  return 0 ;


	case WM_NCHITTEST: // works for any mouse event in this window

	// if the mouse has just changed window, we need to tell the 
	// abandoned window that it has gone (so that it can cancel
	// any tip it may have showing or pending) and then establish
	// this window as current.

	if (hWnd != CurrentWindow) 
	{
		SendMessage(CurrentWindow, WM_COMMAND, WM_MOUSEGONE, 0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

	case WM_MOUSEMOVE:

	mouse.x = mse.x = LOWORD(lParam) ;
	mouse.y = mse.y = HIWORD(lParam) ;

//*****************************************
//  Use the Mouse to drive the Viewer
//*****************************************
	if (wantMousedEp)
	{
		  char date[80] ;
		double tep ;
		PickMseDate(mse.x, date) ;	// get the epoch at the cursor.
		tep = ep ;					// conserve the existing ep.
		ep = MousedEp ;				// substitute the moused epoch.
		update() ;					// update elements to this epoch.
		Systemic(pVSy, UseCentre) ;				// get systemics at this epoch.
		ivrc(hWndView, NULL, FALSE) ;			// display results
		UpdateWindow(hWndView) ;				// in the Viewer
		ep = tep ;									// restore elements
		update() ;
	}

	if (showtips)
		{
			GetCursorPos(&cpt) ;
			ScreenToClient(hWnd, &cpt) ;
 		    GetTip( hWnd, Fos, Fos, cpt ) ;
		}

	// Deal with persistent line cursor, and with the effects
	// on it of any message box!!!

	  activated = 0 ;
	 hActiveWnd = GetActiveWindow() ;
	
		if (hActiveWnd == hWnd)	  
		{						 // this window is active
			if (!wasactive)      // but was not active,  
			{
				wasactive = 1 ;  // so is just activated.
				activated = 1 ;  //(cleared on next mouse move)
			}					 // else is still active.
	    }
		else                     
		{						 // this window is not active
			if (wasactive)       // but was active,
			    wasactive = 0 ;	 // so is just deactivated
		                         // else is still inactive
		}

    if (doFlyers && IsPlotTime &&
		(
		PlotRawDips			||
		PlotRawPeaks		||
		PlotRawTunedDips	||
		PlotRawTunedPeaks	||
		PlotMeanDips		||
		PlotMeanPeaks		||
		PlotMeanTunedDips	||
		PlotMeanTunedPeaks
		)
	   )
	{
		 char  Info[100] ;
		POINT p ;
		  int hits ;

					// TO DO PROPERLY :the line cursor should be shown when the mouse cursor
					// enters the plotting area, and hidden otherwise, but, when in,
					// be hidden the moment the mouse cursor enters _any_ rectangle,
					// _before_ the matching pop-up shows, and (re)shown when the mouse
					// is in no rectangle, _after_ the last remaining pop-up disappears.
					//
					// It should also be hidden if any message box or other window
					// overlays the plot.
					//
					// The "old" line cursor should not be redrawn (for erasure)
					// when the plot is first activated, or re-activated.

	  static  wasinrpk[200] ;
	  static  wasinmpk[200] ;
	  static wasintrpk[200] ;
	  static wasintmpk[200] ;
	  static  wasinrdp[200] ;
	  static  wasinmdp[200] ;
	  static wasintrdp[200] ;
	  static wasintmdp[200] ;

			for ( i = 0, hits = 0 ; i < 200; i++ )
			{
	//if showing peaks of synthesised raw lambda data
				if (PtInRect(&rcRawPeak[i], mouse))
				{ // the mouse is in a raw peak rect now
				   if (!wasinrpk[i])  // if it was not in, then it has lately arrived.
				   {
					wasinrpk[i] = 1 ;	// note arrival.
					++hits ;			// up hit count by one for this pass.
					if (PlotRawPeaks)	// are we are actually wanting this?
					{ // yep, we are; show the pop up 
						sprintf(Info," Raw Peak Shift %3.2fd ", pSamp->rpkShift[i]) ;
						GetCursorPos(&p) ;
						MakeOverlay(0,  p.x + 10, p.y - 30 * hits, Info) ;
					}
				   } // else was in, so is still in and moving: do nothing.
				}
				else
				{ // mouse is not in a raw peak rect right now
					if (wasinrpk[i])		// if it was in, it has just left,
					{
					wasinrpk[i] = 0 ;		// note absence.
					if (hits) --hits ;      // drop hit count by one, unless already nil.
					if (PlotRawPeaks)		// a pop up should be showing: try to lose it.
						{				
						if (hWndInfo[0] != NULL)		// if the pop up really exists,
						DestroyWindow(hWndInfo[0]) ;	// kill it.
						}
					}// else mouse is not in, and was not in, so is still out, do nothing.
				}

	//if showing peaks of synthesised mean lambda data
				if (PtInRect(&rcMeanPeak[i], mouse))
				{
				   if (!wasinmpk[i])
				   {
				   wasinmpk[i] = 1 ;
				   ++hits ;
				   {
					if (PlotMeanPeaks)
						{
						sprintf(Info," Mean Peak Shift %3.2f d ", pSamp->mpkShift[i]) ;
						GetCursorPos(&p) ;
						MakeOverlay(1,  p.x + 10, p.y - 30 * hits, Info) ;
						}
				   }
				   }// else was in, so is still in, do nothing.
				}
				else
				{ // is not in a rect
					if (wasinmpk[i])    // if was in, has left,
					{
					wasinmpk[i] = 0 ;
					if (hits) --hits ;
					if (PlotMeanPeaks)
					{				
						if (hWndInfo[1] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[1]) ;
					}
					}
				}// else was not in, so is still out, do nothing.


	//if showing peaks of tuned raw synthesised lambda data
				if (PtInRect(&rctunedRawPeak[i], mouse))
				{ // in now
				   if (!wasintrpk[i]) // has arrived
				   {
					wasintrpk[i] = 1 ;	// note arrival
					++hits ;
					{
						sprintf(Info," Tuned Raw Peak Shift %3.2f d ", pSamp->trpkShift[i]) ;
						GetCursorPos(&p) ;
						MakeOverlay(2,  p.x + 10, p.y - 30 * hits, Info) ;
					}
				   } // else was in, so is still in, do nothing.
				}
				else
				{ // not in now
					if (wasintrpk[i])    // if was in, has left,
					{				
					wasintrpk[i] = 0 ;
					if (hits) -- hits ;
					if (PlotRawTunedPeaks)
					{
						if (hWndInfo[2] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[2]) ;
					}
					}// else was not in, so is still out, do nothing.
				}

	//if showing peaks of tuned mean synthesised lambda data
				if (PtInRect(&rctunedMeanPeak[i], mouse))
				{
				   if (!wasintmpk[i]) // if it wasn't in, is in now, so has lately arrived
				   {
				   wasintmpk[i] = 1 ;
				   ++hits ;
				   if (PlotMeanTunedPeaks)
				   {
						sprintf(Info," Tuned Mean Peak Shift %3.2f d ", pSamp->tmpkShift[i]) ;
						GetCursorPos(&p) ;
						MakeOverlay(3,  p.x + 10, p.y - 30 * hits, Info) ;
				   }
				   } // else was in, so is still in, do nothing.
				}
				else // is not in a rect
				{
					if (wasintmpk[i])    // if was in, it has left,
					{				
					wasintmpk[i] = 0 ;
					if (hits) --hits ;
				    if (PlotMeanTunedPeaks)
					{
						if (hWndInfo[3] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[3]) ;
					}
					}// else was not in, so is still out, do nothing.
				}

	//if showing raw dips
				if (PtInRect(&rcRawDip[i], mouse))
				{
				   if (!wasinrdp[i])
				   {
					wasinrdp[i] = 1 ;
					++hits ;
					if (PlotRawDips)
					{
					sprintf(Info," Raw Dip Shift %3.2f d ", pSamp->rdpShift[i]) ;
					GetCursorPos(&p) ;
					MakeOverlay(4,  p.x + 10, p.y - 30 * hits, Info) ;
					}
					}// else was in, so is still in, do nothing.
				}
				else
				{ // is not in a rect
					if (wasinrdp[i])    // if was in, has left,
					{				
					wasinrdp[i] = 0 ;
					if(hits) --hits ;
					if (PlotRawDips)
					{
						if (hWndInfo[4] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[4]) ;
					}
					}// else was not in, so is still out, do nothing.
				}

	//if showing mean dips
				if (PtInRect(&rcMeanDip[i], mouse))
				{
				  if (!wasinmdp[i])
				  {
				   wasinmdp[i] = 1 ;
				   ++hits ;
				   if (PlotMeanDips)
				   {
					sprintf(Info," Mean Dip Shift %3.2f d ", pSamp->mdpShift[i]) ;
					GetCursorPos(&p) ;
					MakeOverlay(5,  p.x + 10, p.y - 30 * hits, Info) ;
				   }
				   }// else was in, so is still in, do nothing.
				}
				else
				{ // is not in a rect
					if (wasinmdp[i])    // if was in, has left,
					{				
					wasinmdp[i] = 0 ;
					if (hits) --hits ;
					if (PlotMeanDips)
					{
						if (hWndInfo[5] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[5]) ;
					}
					}// else was not in, so is still out, do nothing.
				}

	//if showing tuned raw dips
				if (PtInRect(&rctunedRawDip[i], mouse))
				{
				   if (!wasintrdp[i])
				   {
					wasintrdp[i] = 1 ;
					++hits ;
					if (PlotRawTunedDips)
					{
					sprintf(Info," Tuned Raw Dip Shift %3.2f d ", pSamp->trdpShift[i]) ;
					GetCursorPos(&p) ;
					MakeOverlay(6,  p.x + 10, p.y - 30 * hits, Info) ;
					}
					}
					// else was in, so is still in, do nothing.
				}
				else // is not in a rect
				{
					if (wasintrdp[i])    // if was in, has left,
					{				
						wasintrdp[i] = 0 ;
						if (hits) --hits ;
						if (PlotRawTunedDips)
						{
						if (hWndInfo[6] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[6]) ;
						}
					}// else was not in, so is still out, do nothing.
				}

	//if showing tuned mean dips
				if (PtInRect(&rctunedMeanDip[i], mouse))
				{
				   if (!wasintmdp[i])
				   {
					wasintmdp[i] = 1 ;
					++hits ;
					if (PlotMeanTunedDips)
					{
					sprintf(Info," Tuned Mean Dip Shift %3.2f d ", pSamp->tmdpShift[i]) ;
					GetCursorPos(&p) ;
					MakeOverlay(7,  p.x + 10, p.y - 30 * hits, Info) ;
					}
				   }// else was in, so is still in, do nothing.
				}
				else // is not in a rect
				{
					if (wasintmdp[i])    // if was in, has left,
					{				
					wasintmdp[i] = 0 ;
					if (hits) --hits ;
					if (PlotMeanTunedDips)
					{
						if (hWndInfo[7] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[7]) ;
					}
					}// else was not in, so is still out, do nothing.
				}
			}
		}

	if (doFlyers && IsPlotOrder &&
			(
			     PlotAlAmp ||
			 AmpliSpectrum ||
			 mAmpliSpectrum
			)
	   )
	{
		      static hits ;
			    char szInfo[255] ;
		   LPFOURIER f ;
		 static char *str[] = {"RAW Lambda", "MEAN Lambda", "ALIGNMENT"} ;
	  static	  POINT cp ;
	  static   wasinamp[200] ;
	  static  wasinmamp[200] ;
	  static wasinAlamp[200] ;

	  if (AmpliSpectrum && ((f = pSamp) != NULL))
		  for ( i = 0 ; i < f->Peaks ; i++)
		  {
			  if (PtInRect(&f->rcPeak[i], mouse)) // is in now
			  {
				  if(!wasinamp[i])	
				  {
					  // was not in, so has just arrived
					  wasinamp[i] = 1 ;	// note arrival
					  ++hits ;			// increment number of hits
				 sprintf(szInfo,
                       " %s\n " \
					   " Order_____ %4.3f        \n " \
                       " Period____ %4.3f days   \n " \
                       " Amplitude_ %4.3f        \n " \
                       " Frequency_ %4.3f c/d    \n " \
                       " Phase_____ %4.3f degs   \n " \
                       " PhaseTime_ %4.3f days      ",
								str[0],								// Type of Spectrum
								f->ordPeak[i],						// Order of Peak
								align->period / f->ordPeak[i],		// Period in days of Peak's order
								f->spcPeak[i],						// Amplitude of Peak
								f->ordPeak[i] / align->period,		// Frequency of Peak in cycles/day
								f->phaPeak[i] * r2d,				// Phase angle in degrees
								0.0									// Period in days of Phase angle (0.0 for now)
								) ;

					GetCursorPos(&cp) ;
					MakeOverlay(0,  cp.x + 20 * hits, cp.y - 50, szInfo) ;
				  }
				  // else is still in, do nothing
			  }
			  else // is not in now
				  if (wasinamp[i]) // was it in?
				  {
						// it was in, so has just left
						wasinamp[i] = 0 ;	// note departure
						if (hits) --hits ;	// decrement hits if not already nil
						if (hWndInfo[0] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[0]) ;
				  }
		  }

	  if (mAmpliSpectrum && ((f = pSamp) != NULL))
		  for ( i = 0 ; i < f->mPeaks ; i++)
		  {
			  if (PtInRect(&f->rcmPeak[i], mouse)) // is in now
			  {
				  if(!wasinmamp[i]) // was it in?	
				  {
					  // was not in, so has just arrived
					  wasinmamp[i] = 1 ;	// note arrival
					  ++hits ;				// increment number of hits
				 sprintf(szInfo,
                       " %s\n " \
					   " Order_____ %4.3f        \n " \
                       " Period____ %4.3f days   \n " \
                       " Amplitude_ %4.3f        \n " \
                       " Frequency_ %4.3f c/d    \n " \
                       " Phase_____ %4.3f degs   \n " \
                       " PhaseTime_ %4.3f days      ",
								str[1],								// Type of Spectrum
								f->ordPeak[i],						// Order of Peak
								align->period / f->ordPeak[i],		// Period in days of Peak's order
								f->spcPeak[i],						// Amplitude of Peak
								f->ordPeak[i] / align->period,		// Frequency of Peak in cycles/day
								f->phaPeak[i] * r2d,				// Phase angle in degrees
								0.0									// Period in days of Phase angle (0.0 for now)
								) ;
					GetCursorPos(&cp) ;
					MakeOverlay(1,  cp.x + 20 * hits, cp.y - 50, szInfo) ;
				  }
				  // else is still in, do nothing
			  }
			  else // is not in now
				  if (wasinmamp[i]) // was it in?
				  {
						// it was in, so has just left
						wasinmamp[i] = 0 ;	// note departure
						if (hits) --hits ;	// decrement hits if not already nil
						if (hWndInfo[1] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[1]) ;
				  }
		  }

	  if (PlotAlAmp && ((f = pAlFou) != NULL))
		  for ( i = 0 ; i < f->Peaks ; i++)
		  {
			  if (PtInRect(&f->rcPeak[i], mouse)) // is in now
			  {
				  if(!wasinAlamp[i])	// was it in?	
				  {
					  // was not in, so has just arrived
					  wasinAlamp[i] = 1 ;	// note arrival
					  ++hits ;			// increment number of hits
				 sprintf(szInfo,
                       " %s\n " \
					   " Order_____ %4.3f        \n " \
                       " Period____ %4.3f days   \n " \
                       " Amplitude_ %4.3f        \n " \
                       " Frequency_ %4.3f c/d    \n " \
                       " Phase_____ %4.3f degs   \n " \
                       " PhaseTime_ %4.3f days      ",
								str[2],								// Type of Spectrum
								f->ordPeak[i],						// Order of Peak
								align->period / f->ordPeak[i],		// Period in days of Peak's order
								f->spcPeak[i],						// Amplitude of Peak
								f->ordPeak[i] / align->period,		// Frequency of Peak in cycles/day
								f->phaPeak[i] * r2d,				// Phase angle in degrees
								0.0									// Period in days of Phase angle (0.0 for now)
								) ;
					GetCursorPos(&cp) ;
					MakeOverlay(2,  cp.x + 20 * hits, cp.y - 50, szInfo) ;
				  }
				  // else is still in, do nothing
			  }
			  else // is not in now
				  if (wasinAlamp[i]) // was it in?
				  {
						// it was in, so has just left
						wasinAlamp[i] = 0 ;	// note departure
						if (hits) --hits ;	// decrement hits if not already nil
						if (hWndInfo[2] != NULL)    // so if flyer, kill it.
						DestroyWindow(hWndInfo[2]) ;
				  }
		  }
	}

	// draw line cursors
	if (!doFlyers)
		while (!LineCursor(hWnd, lcursorhide, &wasin, &activated, D, mouse)) ;	
	
		break ;

	case WM_LBUTTONDOWN:

	mouse.x = LOWORD(lParam) ;
	mouse.y = HIWORD(lParam) ;

	if (st.TimeSeries && _is.AlignsExist && first_al_to_show)
	{
		   static char * altype[] = {"Opposition to", "Conjunction with"} ;

		for ( i = first_al_to_show ; i <= is_al ; i++ )
		{
		 if (PtInRect(&rcalig[i],mouse))
		 {
    		 sprintf(
				     buffer, "Moon in %s %s on %s at %s GMT",
					 altype[Date_Time[UsePlanet][i]->conj],
					 plname[UsePlanet],
					 Date_Time[UsePlanet][i]->aldate,
					 Date_Time[UsePlanet][i]->altime
					) ;

			SetWindowText(hWnd, buffer) ;
		 }
		}

		for ( i = first_al_to_show ; i <= is_al ; i++ )
		{
		 if (PtInRect(&rcmodalig[i],mouse))
		 {
    		 sprintf(
				     buffer, "Modified Moon in %s %s on %s at %s GMT",
					 altype[modDate_Time[UsePlanet][i]->conj],
					 plname[UsePlanet],
					 Date_Time[UsePlanet][i]->aldate,
					 Date_Time[UsePlanet][i]->altime
					) ;

			SetWindowText(hWnd, buffer) ;
		 }
		}

		for ( i = first_al_to_show + 1 ; i <= is_al ; i++ )
		{
		 if (PtInRect(&rcinter_al[i],mouse))
		 {
			 sprintf(buffer,"%s: I.A.P. %4.2f days.",
				     plname[UsePlanet],
				     Date_Time[UsePlanet][i]->epal - Date_Time[UsePlanet][i-1]->epal) ;
			 SetWindowText(hWnd, buffer) ;
		 }
		}
	}

#include "PutPeakTexts.h" // Date Clicking is in this file

		break ;
  
	case WM_LBUTTONUP:

	xmouse = mouse.x = LOWORD(lParam) ;
	ymouse = mouse.y = HIWORD(lParam) ;

	 // the show control panel button has been clicked
		if (PtInRect(&rctl[Fos],mouse))
		SendMessage(hWnd,WM_COMMAND,IDM_SHOW_SETUP,0L) ;

	 // put up the title bar text.
		SetWindowText(hWnd, szArchWindowTit) ;

	if (st.TimeSeries)
	{
		 if (ShowLambdaScale && PtInRect(&S1, mouse))		// Lambda scale just clicked
		 {
			UseScale = 1 ; updisp() ;
		 }

		 if (AlignmentScaleShowing && PtInRect(&S2, mouse)) // Alignment scale just clicked
		 {
			UseScale = 2 ; updisp() ;
		 }

		 if (DegreeScaleShowing    && PtInRect(&S3, mouse)) // Degree scale just clicked
		 {
			UseScale = 3 ; updisp() ;
		 }
	}

		break ;

    case WM_TIMER:

		switch(wParam)
		{
			case IDT_TIPDWELL:
			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 // This time-out timer kicked in when the tip was shown.
			 // if the cursor is still in the control,
			 // this timer message kills the tip.
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 DestroyWindow(hWndInfo[UseCtl]) ;
				 CurrentTip = (HWND)NULL ;
				 hWndOfCurrentTip = (HWND)NULL ;
			 }
			 // the timer is killed in any event
			 KillTimer(hWnd, IDT_TIPDWELL) ;
			 Dwelling[UseCtl] = 0 ;
				return 0L ;

			case IDT_TIPDEFER:
			// the delay-show timer is killed in any event
			 KillTimer(hWnd,IDT_TIPDEFER) ;
			 Deferred[UseCtl] = 0 ;

			 GetCursorPos(&cupt) ;		    // is ind'p't of WndProc
			 ScreenToClient(hWnd,&cupt) ;	// and mouse capture

			 //Delay-show timer WaitTim kicks in
			 //when cursor enters control:
			 //If cursor still there
			 //on this message, show tip.

			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 PutTip(hWnd, 10, 3) ;
			 }
			 break ;
		}
		return 0L ;
		break ;

	case WM_CREATE:
         bmFOS  =    LoadBitmap(hInst,MAKEINTRESOURCE(IDB_FOU_SETUP)) ;
         bmFOSO =    LoadBitmap(hInst,MAKEINTRESOURCE(IDB_FOU_SETUP_ON)) ;
		 bmAlig =    LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ALIG)) ;
		 bmMercury = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_MERCURY)) ;
		 bmVenus =   LoadBitmap(hInst,MAKEINTRESOURCE(IDB_VENUS)) ;
		 bmMars =    LoadBitmap(hInst,MAKEINTRESOURCE(IDB_MARS)) ;
		 bmJupiter = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_JUPITER)) ;
		 bmSaturn =  LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SATURN)) ;
		 bmUranus =  LoadBitmap(hInst,MAKEINTRESOURCE(IDB_URANUS)) ;
		 bmNeptune = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NEPTUNE)) ;
		 bmSun =     LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SUN)) ;

		 bmphMercury = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PH_MERCURY)) ;
		 bmphVenus =   LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PH_VENUS)) ;
		 bmphMars =    LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PH_MARS)) ;
		 bmphJupiter = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PH_JUPITER)) ;
		 bmphSaturn =  LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PH_SATURN)) ;
		 bmphUranus =  LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PH_URANUS)) ;
		 bmphNeptune = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PH_NEPTUNE)) ;
		 bmphSun =     LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PH_SUN)) ;

		 bmMEP =       LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ALMEANEP)) ;

		 icMean =      LoadIcon(hInst,MAKEINTRESOURCE(IDI_MEAN)) ;
		 icPhase =     LoadIcon(hInst,MAKEINTRESOURCE(IDI_PHASE)) ;
		 icPhShift =   LoadIcon(hInst,MAKEINTRESOURCE(IDI_PHASE_SHIFT)) ;
		 icDate =      LoadIcon(hInst,MAKEINTRESOURCE(IDI_DATE)) ;
		 icDate2 =     LoadIcon(hInst,MAKEINTRESOURCE(IDI_DATE2)) ;
		 icDipRaw =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_RAWDIP)) ;
		 icDipMean =   LoadIcon(hInst,MAKEINTRESOURCE(IDI_MEANDIP)) ;
		 ictDipRaw =   LoadIcon(hInst,MAKEINTRESOURCE(IDI_RAWTUNEDDIP)) ;
		 ictDipMean =  LoadIcon(hInst,MAKEINTRESOURCE(IDI_MEANTUNEDDIP)) ;
		 icPeakRaw =   LoadIcon(hInst,MAKEINTRESOURCE(IDI_RAWPEAK)) ;
		 icPeakMean =  LoadIcon(hInst,MAKEINTRESOURCE(IDI_MEANPEAK)) ;
		 ictPeakRaw =  LoadIcon(hInst,MAKEINTRESOURCE(IDI_RAWTUNEDPEAK)) ;
		 ictPeakMean = LoadIcon(hInst,MAKEINTRESOURCE(IDI_MEANTUNEDPEAK)) ;
		 icStart =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_START_DATE)) ;
		 icEnd =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_END_DATE)) ;

		 icSun =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_IC_SUN)) ;
		 icMer =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_IC_MER)) ;
		 icVen =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_IC_VEN)) ;
		 icMar =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_IC_MAR)) ;
		 icJup =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_IC_JUP)) ;
		 icSat =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_IC_SAT)) ;
		 icUra =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_IC_URA)) ;
		 icNep =	   LoadIcon(hInst,MAKEINTRESOURCE(IDI_IC_NEP)) ;

		 return 0L ;
		break ;

	case WM_DESTROY:

		if (hPanelDlg != (HWND)NULL)
		DestroyWindow(hPanelDlg) ;
		if (hRastDlg != (HWND)NULL)
		DestroyWindow(hRastDlg) ;

		DeleteObject(bmFOS) ;
		DeleteObject(bmFOSO) ;
		DeleteObject(bmAlig) ;
		DeleteObject(bmMEP) ;

		DeleteObject(bmMercury) ;
		DeleteObject(bmVenus) ;
		DeleteObject(bmMars) ;
		DeleteObject(bmJupiter) ;
		DeleteObject(bmSaturn) ;
		DeleteObject(bmUranus) ;
		DeleteObject(bmNeptune) ;
		DeleteObject(bmSun) ;

		DeleteObject(bmphMercury) ;
		DeleteObject(bmphVenus) ;
		DeleteObject(bmphMars) ;
		DeleteObject(bmphJupiter) ;
		DeleteObject(bmphSaturn) ;
		DeleteObject(bmphUranus) ;
		DeleteObject(bmphNeptune) ;
		DeleteObject(bmphSun) ;

		return 0L ;
		break ;

	case WM_PAINT:
		{
		hdc = BeginPaint(hWnd, &ps) ;

		oFnt = SelectObject(hdc, hfnt) ;
		oPen = SelectObject(hdc, blackPen) ;
		oBsh = SelectObject(hdc,GetStockObject(WHITE_BRUSH)) ;

		hmemDC = CreateCompatibleDC(hdc) ;

		if (!FOS)
			SelectObject(hmemDC,bmFOS) ;
		else
			SelectObject(hmemDC,bmFOSO) ;

               BitBlt(hdc, rctl[Fos].left,	  // show button
                           rctl[Fos].top,
                           rctl[Fos].right  - rctl[Fos].left,
                           rctl[Fos].bottom - rctl[Fos].top,
                      hmemDC, 0, 0, SRCCOPY ) ;

		GetClientRect(hWnd, &rcArc) ;


		SetRect(&D, rcArc.left   + xlmar,        // define the plotting area
					rcArc.top    + yhmar,		 // without the general histogram
			        rcArc.right  - xrmar ,
					rcArc.bottom - ylmar ) ;

		SetRect(&rctxtblock1, D.left + 1,   // define the text area
			                  D.top - 21,
							  D.right,
							  D.top - 1 ) ; 
		
		SetRect(&S1, 0,					   // rects for clicking
			         D.top,				   // scale notations.
					 D.left,
					 D.bottom ) ; 
		
		SetRect(&S2, D.right,
			         D.top,
					 D.right + 22,
					 D.bottom ) ; 
		
		SetRect(&S3, D.right + 23,
			         D.top,
					 D.right + 48,
					 D.bottom ) ; 
		
		Rectangle(hdc,						 // draw the plotting area
			      D.left   - 1,
			      D.top    - 1,
			      D.right  + 2,
			      D.bottom + 2) ;

		 chartwid = wd = D.right  - D.left ;  // width and height of plotting area
		lftmargin = xlmar ;
		rytmargin = xrmar ;
		 charthyt = ht = D.bottom - D.top ;
		botmargin = ylmar ;
		topmargin = yhmar ;

		//--------------------------------------------------------------------------------------------------
		// The DataReady flag removed to allow astronomic functions to work independently of the buds.
		//	If, then, no bud-series is loaded, it is necessary to specify the starting and ending epochs.
		//--------------------------------------------------------------------------------------------------
{
			if (pFourier != NULL) pf = pFourier ;
			if (  pAlFou != NULL) pa = pAlFou ;

	if (GetPlotMode() == 0)	// we are now in the frequency domain
      {
				int pixticks, pixtxt ;
	         double breadth ;
		static char string[] = "00.0"  ;
		static char str[]    = "ORDER ->" ;
	         double top ; // himaj, lomaj, dv_ht ;
		      //int plotminor ;

	        if (pFourier != NULL) pf = pFourier ;
			if (  pAlFou != NULL) pa = pAlFou ;
			if (  pIMFou != NULL) pk = pIMFou ;

		 // Be sure to turn off alignment icons and general alignment markers
		 if (PlotAligns)
		 {
			 PlotAligns = 0 ;
			 CheckDlgButton(hDlgDisplay, IDC_C_ALIG, 0) ;
		 }

		 if (PlotAllAls)
		 {
			 PlotAllAls = 0 ;
			 CheckDlgButton(hDlgSystemicII, IDC_C_ALL_ALS, 0) ;
		 }

		 // define horizontal scale order-limits

		  lo_f = floor(st.ABotOrd) ;    //  largest integer <= lo order 
		  hi_f =  ceil(st.ATopOrd) ;	// smallest integer >= hi order
		 fspan = hi_f - lo_f ;		    // range of order values
	       big = pf->max_order_index ;  // range of order indices

		oFnt = SelectObject(hdc, hfnt1) ;	// font
		SetBkColor(hdc, RGB(255,255,255)) ;
		SetBkMode(hdc, OPAQUE) ;

		  // adjust label spacing

		GetTextExtentPoint32(hdc, string, strlen(string), &sz) ;
		  pixtxt = sz.cx + 4 ;			// pixel width of widest possible tick label
		pixticks = wd / (int)fspan ;	// pixels between horizontal ticks

		// avoid overlap by displaying every breadth label
		 breadth = 1.0 ;			 // start with unit breadth 
		while (breadth * pixticks < pixtxt) breadth++ ;

	    TextOut(hdc, xlmar + 10, D.bottom + 16, str, strlen(str)) ;

  // horizontal axis, vertical divisions

			oPen = SelectObject(hdc, palePen) ;
	for (
	    u  = lo_f ;
        u <= hi_f ;
		u += 0.1
	    )
		{
		  xp = (int)((double)wd * (u - lo_f) / fspan) + xlmar ;
		  if ( u <= hi_f && u >= lo_f)
		  {
			MoveToEx(hdc, xp, D.bottom + 5, NULL ) ;
			LineTo(  hdc, xp, D.top ) ;
		  }
		}
		SelectObject(hdc, oPen) ;

			oPen = SelectObject(hdc, grayPen) ;
	for (
	    u  = lo_f ;
        u <= hi_f ;
		u += 1.0
	    )
		{
		  xp = (int)((double)wd * (u - lo_f) / fspan) + xlmar ;
		  if ( u <= hi_f && u >= lo_f)
		  {
			MoveToEx(hdc, xp, D.bottom + 5, NULL ) ;
			LineTo(  hdc, xp, D.top ) ;
		  }
		}
		SelectObject(hdc, oPen) ;

  // order value labels

  for (
	    u  = lo_f ;
        u <= hi_f ;
		u += breadth
	  )
		{
		  int w ;
		  xp = (int)((double)wd * (u - lo_f) / fspan) + xlmar ;
		  if ( u <= hi_f && u >= lo_f)
		  {
			sprintf(buff,"%2.1f", u) ;
			GetTextExtentPoint32(hdc, buff, w = strlen(buff), &sz) ;
			TextOut(hdc, xp - sz.cx / 2, D.bottom + 5, buff, w) ;
		  }
		}

#include "Plot3MLines.h"
#include "Put360onRight.h"		
//-------------------------------------------------------------------------------------
//    Graph Setup done, Plotting follows.
//-------------------------------------------------------------------------------------

	// Plot the graph(s).

    if (
		 PowerSpectrum ||
		mPowerSpectrum ||
		 AmpliSpectrum ||
		mAmpliSpectrum ||
		     PlotPhase ||
		    mPlotPhase
		)
	{
	  if (PowerSpectrum || AmpliSpectrum || PlotPhase)
	  {
		  if (!_is.LamSpExists)  // if no raw Lambda spectrum -
		  {
			pf->Peaks = 0 ;								 // - go get it.
			SetWindowText(hWndFetch,"Raw Lam. Spect.") ;
			_is.LamSpExists = GetLambdaSpectrum( RAW ) ;
			SetWindowText(hWndFetch,"") ;
		  }
	  }

	  if (mPowerSpectrum || mAmpliSpectrum || mPlotPhase)
	  {
		  if (!_is.mLamSpExists)	  // if no mean Lambda spectrum -
		  {
			pf->mPeaks = 0 ;
			SetWindowText(hWndFetch,"Mean Lam. Spect.") ;	 // - go get it
			_is.mLamSpExists = GetLambdaSpectrum( MEAN ) ;
			SetWindowText(hWndFetch,"") ;
		  }
	  }
		   top = pf->ComMaxamp ;
	}
		SelectObject(hdc, hfnt) ;
		SetBkColor(  hdc, RGB(255,255,255)) ;
		SetTextColor(hdc, RGB(  0,  0,  0)) ;
		SetBkMode(   hdc, OPAQUE) ;
		strcpy(buff, "0.123") ;  // sample string for text sizing
		GetTextExtentPoint32	 // get text sizes
			(
			  hdc,
			  buff,
			  strlen(buff),
			  &sz
			) ;

#include "PlotLambda_PowAmp_Spectra.h"
#include "PlotLambdaPhases.h"
#include "PlotAlignPowPhaseSpectra.h"

	}  // End of plotting in the frequency domain


    if (GetPlotMode() == 1)		// we are now in the time domain
	  {
		   int daysstep ;

		   int q ;
		  char str[10] ;
		   int yrwid ;
		   int monwid ;
		   int daywid ;
		   int hrwid ;
		   int mnwid ;
		   int scwid ;
		   int pixperbigyrlab ;		// pixels per big  year label
		   int pixperweeyrlab ;		// pixels per wee  year label
		   int pixperbigmnlab ;		// pixels per big month label
		   int pixperweemnlab ;		// pixels per wee month label
		   int pixperwklab ;		// pixels per set of week dates
		   int do_yr_name ;
		   int do_wee_yr_name ;
		   int do_mo_name ;
		   int do_wee_mo_name ;
		   int do_hm_name ;
		   int do_ms_name ;
		   int do_mon_marks ;
		   int do_week_marks ;
		   int do_day_marks ;
		   int do_day_num ;
		   int N, M, fnt_ht ;

		double G ;				// grand period of bud data, in days
		double Gs ;				// grand period of bud data, in seconds
		double As ;				// grand period of ast data, in seconds
		double ep1 ;			// first epoch of G, in days
		double ep2 ;			// last epoch of G, in days
		double ppd ;			// horizontal chart pixels per day 
		double Ds ;
		double n ;
		double P ;

				     q = A.iNumImgperpfx[CurrentPfxID] ;			// number of bud instances with this prefix
				BudEp1 = ep1 = A.fEpperpfx[CurrentPfxID][0] ;		// first bud data epoch, in days
				BudEp2 = ep2 = A.fEpperpfx[CurrentPfxID][q-1] ;	// final bud data epoch, in days
				BudGP  = G = BudEp2 - BudEp1  ;					// grand period of bud data, in days

				    Gs = SiDY * BudGP ;			// grand period of bud data, in seconds
					As = SiDY * AstGP ;			// grand period of ast data, in seconds

		if (As >= SiDY) // if AstGP is a day or more
		{
			sitd = SiDY ;			// tick div is one day
			 stu = 1.0 ;			// one day
			using_hours   = 0 ;
			using_minutes = 0 ;
			using_seconds = 0 ;
		}

		if (As < SiDY && As >= SiHR) // less than a day but an hour or more
		{
			sitd = 10.0 * SiMN ;		// tick div is ten minutes
			 stu = 30.0 * 60.0 / SiDY ;	// thirty minutes, expressed in decimal days
			using_hours   = 1 ;
			using_minutes = 0 ;
			using_seconds = 0 ;
		}
		
		if (As < SiHR && As >= SiMN) // less than an hour but a minute or more
		{
			sitd = SiMN ;			// tick div is one minute
			 stu = 60.0 / SiDY ;	// one minute, expressed in decimal days
			using_hours   = 0 ;
			using_minutes = 1 ;
			using_seconds = 0 ;
		}
		
		if (As < SiMN && As >= SiMN) // less than a minute but a second or more
		{
			sitd = 30.0 * SiSC ; // tick div is 30 seconds
			 stu = 1.0 / SiDY ;  // one second, expressed in decimal days
			using_hours   = 0 ;
			using_minutes = 0 ;
			using_seconds = 1 ;
		}
		

			// the lowest chart tick division contains the lowest astron epoch
				n = floor(SiDY * AstEp1 / sitd) ;
				lochart = n * sitd / SiDY ;			// lo chart epoch (decimal days)
			   
			// the highest chart tick division contains the highest astron epoch
				n = floor(SiDY * AstEp2 / sitd) ;
				hichart = (n + 1.0) * sitd / SiDY ;	// hi chart epoch (decimal days)

			// the chart time-plot range, in days
			     tchart = hichart - lochart ;

			// the chart time-plot range, in seconds
				 Ds = SiDY * tchart ;

				  P = 6.0 * align->period ;
			  minor = 0.05 ;
			   HiGH = hi_y = minor * (floor(pf->Hidata / minor) + 1.0) ;
				big = bud - 1 ;

		 if (pf->Lodata == 0.0)
		  LoW = lo_y = 0.0 ;
		 else
		  LoW = lo_y = minor * ( ceil(pf->Lodata / minor) - 1.0) ;

#include "PlotTimeScales.h"
//---------------------------------------------------------------
//			Graph setup done, Time Series plots follow
//---------------------------------------------------------------


#include "PlotGeneral.h"
#include "PlotAlignMarkers.h"
#include "PlotAlignments.h"
#include "PlotDirections.h"


	} // end if (GetPlotMode())

// Aggregate Graph facilities

#include "PlotAgraphs.h"
	
}
        // All done for now.
		// Clean up.
		SelectObject(hmemDC, oBm) ;
		DeleteDC(hmemDC) ;
		SelectObject(hdc, oFnt) ;
		SelectObject(hdc, oPen) ;
		EndPaint(hWnd, &ps) ;
		}
			return 0L ;  // end of WM_PAINT

      default:                  /* Passes it on if unprocessed    */
          return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return ((long)NULL);
}


void plot(
		  HDC hdc, 
		  int xp,
		  int yp, 
		  int oxp[],
		  int oyp[],
		  int i,
		  int s,
		  int t
		 )
{
			if (i == 1 || t)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
}

int FullPhase(
			     HDC hdc,
			    HPEN pen,
			  double oang,
			  double ang,
			     int Sp,
				 int xp,
				 int yp,
				 int oxp,
				 int oyp,
				 int top,
				 int bot
			  )
{
	int ixp, iyp, transit ;
   HPEN oPen ;

	oPen = SelectObject(hdc, pen) ;

	switch(Sp)
	{
		   case 1: transit = 1 ;
			  ixp = (int)((twopi - oang) * (double)(xp - oxp)/(ang - oang)) + oxp ;
			  iyp = top ;
              MoveToEx( hdc, oxp, oyp, NULL ) ;
			  LineTo( hdc, ixp, iyp ) ;
			  iyp = bot ;
              MoveToEx( hdc, ixp, iyp, NULL ) ;
			  LineTo( hdc, xp, yp ) ;
			   break ;
		   case 2: transit = 1 ;
			  ixp = (int)(oang * (double)(xp - oxp)/( oang - ang)) + oxp ;
			  iyp = bot ;
              MoveToEx( hdc, oxp, oyp, NULL ) ;
			  LineTo( hdc, ixp, iyp ) ;
			  iyp = top ;
              MoveToEx( hdc, ixp, iyp, NULL ) ;
			  LineTo( hdc, xp, yp ) ;
			   break ;
		   case 0: 
		   default:transit = 0 ;
			   break ;
	}

	SelectObject(hdc, oPen) ;
	return transit ;
}


/*******************************************************
  Capture Full Window as Bitmap for printing or saving.
 *******************************************************/
HBITMAP Capture(
				HWND hWnd,
				LPPOINT pt // dimensions may be retrieved by caller from this
			   )
{
	HBITMAP hBitmap, oBm ;
	    HDC hwdc, hmemDC ;
	   RECT rcWnd ;

	  GetWindowRect(hWnd, &rcWnd) ;         // get hWnd's  dimens.
      pt->x = rcWnd.right - rcWnd.left ;    // get hWnd's width
	  pt->y = rcWnd.bottom - rcWnd.top ;    // get hWnd's height

	   hwdc = CreateDC( "DISPLAY", NULL, NULL, NULL ) ;// get Screen's DC
	   SetMapMode( hwdc, MM_TEXT ) ;

	 hmemDC = CreateCompatibleDC( hwdc ) ; // mem. DC compat. with hwdc

	hBitmap = CreateCompatibleBitmap(	   // bitmap compat. with hwdc
		                             hwdc,
									 pt->x,
									 pt->y
		                            ) ;

	oBm = SelectObject(hmemDC, hBitmap) ;  // sel. bitmap into mem. DC

	BitBlt(				                   // grab the full window image
		    hmemDC,
			0, 0,
			pt->x,
			pt->y,
			hwdc,
			rcWnd.left,
			rcWnd.top,
			SRCCOPY
		   ) ;

	hBitmap = SelectObject(hmemDC, oBm) ; // get bitmap's handle

	DeleteDC( hmemDC ) ;				  // clear up
	DeleteDC( hwdc ) ;

	return hBitmap ; // send back the Bitmap's handle					  
}

/*********************************************************
 Pick a window for capture to a bitmap.
 Routine lifted from "capture.c" in DibView, and modified.
 *********************************************************/
HWND SelectWindow(HWND hWnd)
{
    POINT pt ;               // Stores mouse position on a mouse click
    HWND hWndClicked ;       // Window we clicked on
	HWND hWndChild ;
    MSG msg ;


 // Send all mouse messages to calling window
    SetCapture(hWnd);

 // Eat mouse messages until a WM_LBUTTONUP is encountered,
 // !!! NB, by the calling window !!!  This is the reason for
 // the mouse capture to that window: the mouse messages could
 // otherwise be missed. 

    for ( ; ; )
	{
    WaitMessage();

    if (PeekMessage(&msg,NULL,WM_MOUSEFIRST,WM_MOUSELAST,PM_REMOVE))
	{
			
            if (msg.message == WM_LBUTTONUP)
			{
               // Get mouse position
                pt.x = LOWORD(msg.lParam);
                pt.y = HIWORD(msg.lParam);

               // Convert to screen coordinates
			      ClientToScreen(hWnd, &pt) ;

               // Get Window that we clicked on
                hWndClicked = WindowFromPoint(pt) ;

               // If it's not a valid window, just return NULL
                if (!hWndClicked)
				{
                    ReleaseCapture();
                    return (HWND)NULL ;
				}

				// convert to mouse coordinates to client
				// of clicked window

				  ScreenToClient(hWndClicked, &pt) ;

		while (TRUE)
            {
            hWndChild = ChildWindowFromPoint(hWndClicked, pt) ;

            if (hWndChild && hWndChild != hWndClicked)
                hWndClicked = hWndChild;
            else
                break;
            }
                break;
            }
        }
    else
        continue;
    }
    ReleaseCapture();
    return (hWndClicked);
}

HWND GrabWindow(
HWND hWndCalling	// window calling this function
)  
{
	  POINT pt ;
static HWND hWndPoint ; // keep the  handle of the most recently grabbed
	   HWND hWndChild ;

		GetCursorPos(&pt) ;
		
		hWndPoint = WindowFromPoint(pt) ;
		
		if (hWndPoint != (HWND)NULL)
		{
		ScreenToClient(hWndPoint, &pt) ;

		while (TRUE)
			{
			hWndChild = ChildWindowFromPoint(hWndPoint, pt) ;
            if (hWndChild && hWndChild != hWndPoint)
                hWndPoint = hWndChild ;
            else
                break;
			}
		}

     return hWndPoint ;
}

HBITMAP GrabWnd( HWND hWnd )
{
	HBITMAP hBitmap, oBm ;
	    HDC hdc, hmemDC ;
	   RECT rc ;

		GetWindowRect(hWnd, &rc) ;
		grabwid = rc.right - rc.left ;
		grabhyt = rc.bottom - rc.top ;
		  grabx = rc.left ;
		  graby = rc.top ;

	   hdc = CreateDC( "DISPLAY", NULL, NULL, NULL ) ;// get Screen's DC
	   SetMapMode( hdc, MM_TEXT ) ;
	 hmemDC = CreateCompatibleDC( hdc ) ;				// mem. DC compat. with hdc
	hBitmap = CreateCompatibleBitmap(hdc, grabwid, grabhyt) ;	// bitmap compat. with hdc
	    oBm = SelectObject(hmemDC, hBitmap) ;			// sel. bitmap into mem. DC

	BitBlt(				                   // grab the full window
		    hmemDC,
			0, 0,
			grabwid,
			grabhyt,
			hdc,
			grabx, graby,   
			SRCCOPY
		   ) ;

	hBitmap = SelectObject(hmemDC, oBm) ; // get bitmap's handle

	DeleteDC( hmemDC ) ;				  // clear up
	DeleteDC( hdc ) ;

	return hBitmap ; // send back the Bitmap's handle
}


/*	   
 *     Apply Tuning.  
 *	   ~~~~~~~~~~~~
 *     Modified April 2002 to allow free specification of input parameters.
 *    (Would actually be better to use a struct for input, I think.)
 */
void DoTunedSynth(
				  LPFOURIER fou,		// data structure to use
				        int N,			// number of data points
						int sFactor,	// multiplier for number of points to synthesize
					 double lo_order,	// least order of band
					 double hi_order,	// largest order of band
					 double * ostep,	// order step
					    int onbuds,		// whether on bud series or general dates
				        int Type		// Data type to use (raw/mean)
				 )
{
	double resonance ;
	// obtain fourier spectrum of the data

	        Spectrum(		 
				fou,
				N,
				ostep,
				hi_order,
				lo_order,
				Type		 // Data type used (raw/mean)
				) ;

   // synthesize the data per the selectivity curve

			resonance = onbuds ? resorderbud : resorder ;  

			Synthesis(
				fou,	      // data structure
				sFactor * N,  // number of points to synthesize
				hi_order,	  // highest order of band
				lo_order,	  // least order of band
				resonance,	  // resonant order
				selectivity,  // selectivity
				gain,		  // gain
				1,		      // Use tuning
				onbuds,		  // whether on bud series or general dates
				Type,		  // Data type used (raw/mean)
				0,            // No forcing
				0,			  // Not alignments
				0,			  // Not integral
				0			  // Not derivative
				) ;
}

// **************************************************************
//                   Selectivity Curve Window
// **************************************************************
long CALLBACK SelectivityProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps ;
	    //POINT mouse ;
	static   HPEN oPen ;
	static HBRUSH oBr ;
	static	HFONT oFnt ;
	static   SIZE sz ;
	static    HDC hdc ;
	static	 RECT rc, Fr, D ;
	static	 char buff[50] = "This is a test string" ;

	static lftmarg = 30 ;
	static rytmarg = 30 ;
	static topmarg = 40 ;
	static botmarg = 30 ;
	static int ht, wd, i, m, xp, yp, len ;


	switch (message)
	{
      case WM_NCHITTEST: // works for a mouse event anywhere in this window

	// If the mouse has moved window, tell the abandoned window so that
	// it can turn off any tip that it might have showing, then make
	// this window officially current. Else preserve status quo.

	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

	  case WM_COMMAND:
		  switch(LOWORD(wParam))
		  {
		   case WM_MOUSEGONE:
			   // The rodent has left the window!
			   // If there is a tip showing, get rid of it.
		       if (CurrentTip != NULL)
			   RemoveTip() ;
		       return 0L ;

		    default: break ;
		  }
		  break ; // end WM_COMMAND

	  case WM_SIZE:
	  case WM_MOVE:
		  ivrc(hWnd, NULL, TRUE) ;
		  break ;

	  case WM_PAINT:
		   hdc = BeginPaint(hWnd, &ps) ;

		  oPen = SelectObject(hdc, blackPen) ;
		  oBr  = SelectObject(hdc, GetStockObject(WHITE_BRUSH)) ;
		  oFnt = SelectObject(hdc, hfnt) ;
		  SetBkMode(hdc, TRANSPARENT) ;
		  GetClientRect(hWnd, &rc) ;

		  wd = (rc.right - rc.left) - (lftmarg + rytmarg) ;
		  ht = (rc.bottom - rc.top) - (botmarg + topmarg) ;

		  SetRect(						  // Frame
			      &Fr,
			      rc.left + lftmarg - 2,
				  rc.top  + topmarg - 2,
				  rc.left + lftmarg + wd + 2,
				  rc.top  + topmarg + ht + 2
	             ) ;

		  Rectangle(
			        hdc,
			        Fr.left,
					Fr.top,
					Fr.right,
					Fr.bottom
				   ) ;

		  SetRect(
			      &D,							// Plotting area
			      rc.left + lftmarg,
				  rc.top  + topmarg,
				  rc.left + lftmarg + wd,
				  rc.top  + topmarg + ht
	             ) ;

		         m = pSamp->max_order_index ;
				 if (wantNotch)					// Invert the transfer function
				 i = pSamp->tauminidx ;
				 else
				 i = pSamp->taumaxidx ;

				 SelectObject(hdc, bluePen) ;

			xp = MulDiv(wd, i, m) + D.left ;
			yp = D.top - 3 ;
			MoveToEx(hdc, xp, yp, NULL) ;
			yp = D.bottom + 3 ;
			LineTo(hdc, xp, yp) ;
			
			sprintf(buff,"%5.3f", resorder) ;
			GetTextExtentPoint32(hdc, buff, len = strlen(buff), &sz) ;
			TextOut(hdc,xp - sz.cx/2, D.bottom + 5, buff, len) ;

			sprintf(buff,"Bandwidth: %5.3f.  (Low: %5.3f,  High: %5.3f)",
				    bandwidth, lo_dB_ord, hi_dB_ord) ;
			GetTextExtentPoint32(hdc, buff, len = strlen(buff), &sz) ;
			TextOut(hdc,D.left / 2, D.top - (sz.cy + 8), buff, len) ;

				 SelectObject(hdc, goldPen) ;

          for ( i = 0 ; i <= m  ; i++ )
		  {
			  double ang ;
			  ang = pSamp->eta[i] ;

			xp = MulDiv(wd, i, m) + D.left ;
			yp = rc.bottom -
				(int)((double)ht * (ang + pi/2.0) / pi + (double)botmarg)  ;

			if (!i)
				MoveToEx(hdc, xp, yp, NULL) ;
			else
				  LineTo(hdc, xp, yp) ;
		  }

				 SelectObject(hdc, redPen) ;

		  for ( i = 0 ; i <= m  ; i++ )
		  {
			xp = MulDiv(wd, i, m) + D.left ;
			yp = rc.bottom -
				(int)((double)ht * pSamp->tau[i] / pSamp->maxtau + (double)botmarg)  ;

			if (!i)
				MoveToEx(hdc, xp, yp, NULL) ;
			else
				  LineTo(hdc, xp, yp) ;
		  }
		  
		  //GetTextExtentPoint32(hdc, buff, strlen(buff), &sz) ;
		  //TextOut(hdc, Fr.left, Fr.bottom + sz.cy/2, buff, strlen(buff)) ;


		  SelectObject(hdc, oPen) ;
		  SelectObject(hdc, oBr ) ;
		  SelectObject(hdc, oFnt) ;

		  EndPaint(hWnd, &ps) ;
		  break ;

      default:                  /* Passes it on if unprocessed    */
          return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return ((long)NULL);
}

/*****************************************************************
					Rasterised Alignments.

	Show selected alignment groups, one group per inter-perigeal
	interval (interval between moments of Moon-in-perigee) per
	vertical line of a "raster".  Show mean epochs of the groups,

 *****************************************************************/
long CALLBACK RasterProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
      PAINTSTRUCT ps ;
	static POINT mouse, cur ;
    static    HDC hdc ;
    static   HPEN pen, oPen ;
    static HBRUSH oBr ;
    static  HFONT oFnt ;
	static  HICON ico ;
	static   SIZE s ;
    static   RECT rc, Fr, D ;
		 static xlm, xrm = 10 ;
		 static xhm = 30, xbm = 30 ;
		 static i, ht, wd, ilpix, xp, yp, p, B ;
   static ULONG gr, a, j ;
   static ULONG oj = 0L, ok = 0L ;
   static char str[50], str1[50], str2[50] ;
   static char gst[] = " PPP. 00 DDD 0000 " ;					// guage string
   
   static double pgint, et, epL, epR, oepL ;

	switch(message)
	{
      case WM_NCHITTEST: // works for a mouse event anywhere in this window

	// If the mouse has moved window, tell the abandoned window so that
	// it can turn off any tip that it might have showing, then make
	// this window officially current. Else preserve status quo.

	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

	  case WM_COMMAND:
		  switch(LOWORD(wParam))
		  {
		   case WM_MOUSEGONE:
			   // The rodent has left the window!
			   // If there is a tip showing in
			   // this window, get rid of it.
		       if (CurrentTip != NULL)
			   RemoveTip() ;
		       return 0L ;

	  case WM_XREF:				// for cross reference
		  break ;

		    default: break ;
		  }
		  return 0L ; // end WM_COMMAND

		  

	  case WM_SIZE:
	  case WM_MOVE:
		  ivrc(hWnd, NULL, TRUE) ;
		  break ;

	  case WM_CREATE:
		  break ;

	  //case WM_DESTROY:
		  //break ;

	  case WM_MOUSEMOVE:
		  {
		static m, hits, hyt, busy = 0, body ;
		static yup = 20, xoff = 100 ;
		static        wasinrawdip[MAXPEAKS] ;
		static       wasinmeandip[MAXPEAKS] ;
		static       wasinrawpeak[MAXPEAKS] ;
		static      wasinmeanpeak[MAXPEAKS] ;
		static   wasintunedrawdip[MAXPEAKS] ;
		static  wasintunedmeandip[MAXPEAKS] ;
		static  wasintunedrawpeak[MAXPEAKS] ;
		static wasintunedmeanpeak[MAXPEAKS] ;
		static         wasinalign[MAXALS]   ;
		static         wasinpreds[MAXALS]   ;
		  char string[256] ;

			mouse.x = LOWORD(lParam) ;
			mouse.y = HIWORD(lParam) ;

				body = UsePlanet ;
				hits = 0 ;
  // Alignments
			for (m = 0, hyt = 40 ; m < MAXALS ; m++)
			{
				if (PtInRect(&rcRastAl[m], mouse))
				{
					// is in now
					if (!wasinalign[m])
					{// but was not, so has lately arrived
						wasinalign[m] = 1 ; // note arrival
						hits++ ;
						if (wantAlsXref)	// signal to draw rectangle
							SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, AL)) ;
						if (wantAlPopups && RastBodyList[Als.Bodyof[m]])
								{
									et = ep ;
									ep = Als.Alepof[m] ; civildate() ;
									ep = et ;
								    sprintf(string,
                                    "  Alignment %d with %s\n" \
                                    "  on %s\n" \
                                    "      at %2.2d:%2.2d GMT",
                                    m + 1, plname[Als.Bodyof[m]], dayt, hr, mn ) ;
									GetCursorPos(&cur) ;
									MakeOverlay(28, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
					}
				}
				else 
				{// is not in now
					if (wasinalign[m])
					{ // but was in, so has lately left
						wasinalign[m] = 0 ;		// note departure
						if (hits) --hits ;		// decrement count of all hits on this pass
						// signal to cancel rectangle
						if (wantAlsXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, AL)) ;
						if (wantAlPopups) {	if (hWndInfo[28] != (HWND)NULL) DestroyWindow(hWndInfo[28]) ; }
					}
				}
			}

  // Other Events
			for (m = 0, hyt = 70 ; m < MAXPEAKS ; m++)
			{

			// UNTUNED DIP

					// RAW UNTUNED DIP
				if (PtInRect(&rcRastRawDip[m], mouse))
					{
					// is in now
						if (!wasinrawdip[m])
						{// but was not, so has lately arrived
							wasinrawdip[m] = 1 ;
							++hits ;			 // count any kind of hit occurring on this pass
							if (RastRawDips)	 // dealing with untuned raw dips
							{
							// this will apply only to the going item type, whether or not popup info
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, URDP)) ;
							// give pop up info on the going type 
							if (wantPDPopups)	
								{
									et = ep ;
									ep = Samp.DipEps[m] ; civildate() ;
									ep = et ;
								    sprintf(string,
                                    "  Raw untuned dip %d on\n  %s\n" \
                                    "  at %2.2d:%2.2d GMT\n" \
                                    "  True Shift wrt %s: %5.2f days\n" \
                                    "  Raster shifted by %5.2f days",
                                    m + 1, dayt, hr, mn, plname[body], Samp.rdpShift[m], -leadlag) ;
									GetCursorPos(&cur) ;
									MakeOverlay(20, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
							}
						}	// else still in, maintain status quo
					}
				else 
					{	// is not in now
						if (wasinrawdip[m])
						{ // but was in, so has lately left
							wasinrawdip[m] = 0 ;	// note departure
							if (hits) --hits ;		// decrement count of all hits on this pass
							if (RastRawDips)		// dealing with raw untuned dips
							{
							// cancel any rectangle
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, URDP)) ;
							if (wantPDPopups) {	if (hWndInfo[20] != (HWND)NULL) DestroyWindow(hWndInfo[20]) ; }
							}
						}
						// else has not lately arrived
					}

					// MEAN UNTUNED DIP
				if (PtInRect(&rcRastMeanDip[m], mouse))
					{
					// is in now
						if (!wasinmeandip[m]) // has just arrived
						{
							wasinmeandip[m] = 1 ; // note arrival
							++hits ;
							if (RastMeanDips)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, UMDP)) ;
							if (wantPDPopups)
								{
								et = ep ;
								ep = Samp.mDipEps[m] ; civildate() ;
								ep = et ;
                                sprintf(string,
                               "  Mean untuned dip %d on\n  %s  \n" \
                               "  at %2.2d:%2.2d GMT\n  " \
                               "  True Shift wrt %s: %5.2f days  \n" \
                               "  Raster shifted by %5.2f days  ",
                                m + 1, dayt, hr, mn, plname[body], Samp.mdpShift[m] , -leadlag) ;
								GetCursorPos(&cur) ;
								MakeOverlay(21, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
							}
						}
					// else still in, maintain status quo
					}
				else 
					{// is not in now
						if (wasinmeandip[m]) 
						{// but was in, so has lately left
							wasinmeandip[m] = 0 ; // note departure
							if (hits) --hits ;
							if (RastMeanDips)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, UMDP)) ;
							if (wantPDPopups) {	if (hWndInfo[21] != (HWND)NULL) DestroyWindow(hWndInfo[21]) ;}
							}
						} // else has not arrived
					}


			// UNTUNED PEAK

					// RAW UNTUNED PEAK
				if (PtInRect(&rcRastRawPeak[m], mouse))
					{// is in now
						if (!wasinrawpeak[m]) // but was not, so has lately arrived
						{
							wasinrawpeak[m] = 1 ; // note arrival
							++hits ;
							if (RastRawPeaks)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, URPK)) ;
							if (wantPDPopups)
								{
								et = ep ;
								ep = Samp.PeakEps[m] ; civildate() ;
								ep = et ;
                                sprintf(string, 
                               "  Raw untuned peak %d on\n  %s\n" \
                               "  at %2.2d:%2.2d GMT\n" \
                               "  True Shift wrt %s: %5.2f days\n" \
                               "  Raster shifted by %5.2f days",
                                m + 1, dayt, hr, mn, plname[body], Samp.rpkShift[m], -leadlag) ;
								GetCursorPos(&cur) ;
								MakeOverlay(22, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
							}
						} // else is still in, maintain status quo
					}
				else
					{ // is not in now
						if (wasinrawpeak[m])
						{ // but was in so has lately left
							wasinrawpeak[m] = 0 ; // note departure
							if (hits) --hits ;
							if (RastRawPeaks)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, URPK)) ;
							if (wantPDPopups){if (hWndInfo[22] != (HWND)NULL) DestroyWindow(hWndInfo[22]) ;}
							}
						}
						// else has not arrived
					}

					// MEAN UNTUNED PEAK

				if (PtInRect(&rcRastMeanPeak[m], mouse))
					{// is in now
						if (!wasinmeanpeak[m]) // has just arrived
						{
							wasinmeanpeak[m] = 1 ; // note arrival
							++hits ;
							if (RastMeanPeaks)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, UMPK)) ;
							if (wantPDPopups)
								{
								et = ep ;
								ep = Samp.mPeakEps[m] ; civildate() ;
								ep = et ;
                                sprintf(string, 
                               "  Mean untuned peak %d on\n  %s\n" \
                               "  at %2.2d:%2.2d GMT\n" \
                               "  True Shift wrt %s: %5.2f days\n" \
                               "  Raster shifted by %5.2f days",
                                m + 1, dayt, hr, mn, plname[body], Samp.mpkShift[m], -leadlag) ;
								GetCursorPos(&cur) ;
								MakeOverlay(23, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
							}
						}	//  else still around, maintain status quo
					}
				else // is not in now
					{
						if (wasinmeanpeak[m]) // has left
						{
							wasinmeanpeak[m] = 0 ; // note departure
							if (hits) --hits ;
							if (RastMeanPeaks)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, UMPK)) ;
							if (wantPDPopups) {if (hWndInfo[23] != (HWND)NULL)	DestroyWindow(hWndInfo[23]) ;}
							}
						}
						// else has not arrived
					}


			// TUNED DIP

					// RAW TUNED DIP
				if (PtInRect(&rcRastTunedRawDip[m],   mouse))
					{// is in now
						if (!wasintunedrawdip[m])// has arrived
						{
							wasintunedrawdip[m] = 1 ; // note arrival
							++hits ;
							if (RastTunedRawDips)
							{
								if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, TRDP)) ;
								if (wantPDPopups)
								{
								et = ep ;
								ep = Samp.tDipEps[m] ; civildate() ;
								ep = et ;
                                sprintf(string, 
                               "  Raw tuned dip %d on\n  %s\n" \
                               "  at %2.2d:%2.2d GMT\n" \
                               "  True Shift wrt %s: %5.2f days\n" \
                               "  Raster shifted by %5.2f days",
                                m + 1, dayt, hr, mn, plname[body], Samp.trdpShift[m], -leadlag) ;
								GetCursorPos(&cur) ;
								MakeOverlay(24, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
							}
						} // still around
					}
				else
					{ // is not in now
						if (wasintunedrawdip[m]) // has lately left
						{
							wasintunedrawdip[m] = 0 ; // note departure
							if (hits) --hits ;
							if (RastTunedRawDips)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, TRDP)) ;
							if (wantPDPopups) {if (hWndInfo[24] != (HWND)NULL) DestroyWindow(hWndInfo[24]) ;}
							}
						}
						// else has not arrived
					}

					// MEAN TUNED DIP
				if (PtInRect(&rcRastTunedMeanDip[m],  mouse))
					{
					// is in now
						if (!wasintunedmeandip[m]) // has arrived
						{
							wasintunedmeandip[m] = 1 ; // note arrival
							++hits ;
							if (RastTunedMeanDips)
							{
								if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, TMDP)) ;
								if (wantPDPopups)
								{
								et = ep ;
								ep = Samp.tmDipEps[m] ; civildate() ;
								ep = et ;
                                sprintf(string, 
                               "  Raw tuned dip %d on\n  %s\n" \
                               "  at %2.2d:%2.2d GMT\n" \
                               "  True Shift wrt %s: %5.2f days\n" \
                               "  Raster shifted by %5.2f days",
                                m + 1, dayt, hr, mn, plname[body], Samp.trdpShift[m], -leadlag) ;
								GetCursorPos(&cur) ;
								MakeOverlay(25, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
							}
						} // still around
					}
				else 
					{// is not in now
						if (wasintunedmeandip[m]) // has left
						{
							wasintunedmeandip[m] = 0 ; // note departure
							if (hits) --hits ;
							if (RastTunedMeanDips)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, TMDP)) ;
							if (wantPDPopups) {if (hWndInfo[25] != (HWND)NULL)	DestroyWindow(hWndInfo[25]) ;}
							}
						}
						// else has not arrived
					}


			// TUNED PEAK

					// RAW TUNED PEAK
				if (PtInRect(&rcRastTunedRawPeak[m], mouse))
					{
					// is in now
						if (!wasintunedrawpeak[m]) // has lately arrived
						{
							wasintunedrawpeak[m] = 1 ; // note arrival
							++hits ;
							if (RastTunedRawPeaks)
							{
								if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, TRPK)) ;
								if (wantPDPopups)
								{
								et = ep ;
								ep = Samp.tPeakEps[m] ; civildate() ;
								ep = et ;
                                sprintf(string, 
                               "  Raw tuned peak %d on\n  %s\n" \
                               "  at %2.2d:%2.2d GMT\n" \
                               "  True Shift wrt %s: %5.2f days\n" \
                               "  Raster shifted by %5.2f days",
                                m + 1, dayt, hr, mn, plname[body], Samp.trpkShift[m], -leadlag) ;
								GetCursorPos(&cur) ;
								MakeOverlay(26, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
							}
						} // still around
					}
				else // is not in now
					{
						if (wasintunedrawpeak[m]) // has left
						{
							wasintunedrawpeak[m] = 0 ; // note departure
							if (hits) --hits ;
							if (RastTunedRawPeaks)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, TRPK)) ;
							if (wantPDPopups) {if (hWndInfo[26] != (HWND)NULL)	DestroyWindow(hWndInfo[26]) ;}
							}
						}
						// else has not arrived
					}

					// MEAN TUNED PEAK

				if (PtInRect(&rcRastTunedMeanPeak[m], mouse))
					{// is in now

						if (!wasintunedmeanpeak[m]) // has lately arrived
						{
							wasintunedmeanpeak[m] = 1 ; // note arrival
							++hits ;
							if (RastTunedMeanPeaks)
							{
								if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, TMPK)) ;
								if (wantPDPopups)
								{
								et = ep ;
								ep = Samp.tmPeakEps[m] ; civildate() ;
								ep = et ;
                                sprintf(string, 
                               "  Mean tuned peak %d on\n  %s\n" \
                               "  at %2.2d:%2.2d GMT\n" \
                               "  True Shift wrt %s: %5.2f days\n" \
                               "  Raster shifted by %5.2f days\n",
                                m + 1, dayt, hr, mn, plname[body], Samp.tmpkShift[m], -leadlag) ;
								GetCursorPos(&cur) ;
								MakeOverlay(27, cur.x - xoff, cur.y - yup - hits * hyt, string) ;
								}
							} // still around
						}
					}
				else
					{ // is not in now
						if (wasintunedmeanpeak[m]) // has left
						{
							wasintunedmeanpeak[m] = 0 ; // note departure
							if (hits) --hits ;
							if (RastTunedMeanPeaks)
							{
							if (wantXref) SendMessage(hWndArch, WM_COMMAND, WM_XREF, MAKELPARAM(m, TMPK)) ;
							if (wantPDPopups) {if (hWndInfo[27] != (HWND)NULL)	DestroyWindow(hWndInfo[27]) ;}
							}
						}
						// else has not arrived
					}
			}
		  }
		  break ;

	case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps) ;

		   oPen = SelectObject(hdc, blackPen) ;
		   oBr  = SelectObject(hdc, WHITE_BRUSH) ;
		   oFnt = SelectObject(hdc, hfnt1) ;
		   SetBkMode(hdc, TRANSPARENT) ;

		  GetClientRect(hWnd, &rc) ;

		  ilpix = ht / Als.nGrps ;								// proposed inter raster line pixels
		  GetTextExtentPoint32(hdc, gst, strlen(gst), &s) ;		// pixel dimensions of guage string

		  if (wantAxialLabels && (ilpix > 2 * s.cy))			// make space for axial labels 
				xlm = s.cx + 4 ;								// left margin for date/time strings
		  else
				xlm = 10 ;										// left margin without date/time strings 
			
			SetRect(&Fr, rc.left   + xlm,
						 rc.top    + xhm,
						 rc.right  - xrm,
						 rc.bottom - xbm ) ;

			SetRect(&D, Fr.left   - 1,
						Fr.top    - 1,
						Fr.right  + 1,
						Fr.bottom + 1 ) ;

			Rectangle(hdc, D.left,
						   D.top,
						   D.right,
						   D.bottom ) ;

			ht = Fr.bottom - Fr.top ;
			wd = Fr.right - Fr.left ;

	for ( p = MER ; p <= SUN ; p++)
	{
		if (p == PLU) continue ;
		oxp[p] = oyp[p] = 0 ;
	}

	for ( gr = 0L ; gr <= Als.nGrps ; gr++ )
	{
		double e ;

		// height of current raster line
			yp = Fr.top + ht * gr / Als.nGrps ;

		// draw the raster line
			if (ilpix > s.cy)
			{
				oPen = SelectObject(hdc, palePen) ;
				xp = Fr.left ;
				MoveToEx(hdc, xp, yp, NULL) ;
				xp = Fr.right ;
				LineTo(hdc, xp, yp) ;
				SelectObject(hdc, oPen) ;
			}

			if (gr == 0L)
			{
				epL = Als.EpAx[gr] - 13.777275 ;  // leftmost start epoch of first raster line
			    epR = Als.EpAx[gr] ;
			}

	// Dec. 2005 bug fix: the final group was neither being displayed nor used

			if ((gr > 0L) && (gr < Als.nGrps)) 
			{
				epL = Als.EpAx[gr - 1] ;
				epR = Als.EpAx[gr] ;
			}

			if (gr == Als.nGrps)
			{
				epL = Als.EpAx[gr - 1] ;
				epR = Als.EpAx[gr - 1] + 13.777275 ; // rightmost end epoch of last raster line
			}

			// the current interaxial interval
			// (ought to be constant - and is, to 8 significant places)

			pgint = epR - epL ;

			// annotate the Axial epochs
			if (wantAxialLabels && (ilpix > 2 * s.cy))
			{
				et = ep ;
				ep = epL ; civildate() ; // returns the date and time
				ep = et ;
				if (Als.Axtyp[gr])
				sprintf(str1, "Pg %2.2d %s %4.4d  ", day, szMonth[mo], yr) ; // use short-form month name
				else
				sprintf(str1, "Ag %2.2d %s %4.4d  ", day, szMonth[mo], yr) ; // use short-form month name
				GetTextExtentPoint32(hdc, str1, strlen(str1), &s) ;
				TextOut(hdc, Fr.left - s.cx, yp - s.cy, str1, strlen(str1)) ;
				sprintf(str1, " at %2.2d:%2.2d GMT", hr, mn) ; 
				GetTextExtentPoint32(hdc, str1, strlen(str1), &s) ;
				TextOut(hdc, Fr.left - (s.cx + 4), yp, str1, strlen(str1)) ;
			}

			// mark the opening epoch of the Grand Period
			if (gr == 0L)
			{
				xp = Fr.left +  (int)((double)wd * (AstEp1 - epL) / pgint) ;
				DrawIcon(hdc, xp, yp, icStart) ;
				et = ep ;
				ep = AstEp1 ; civildate() ;
				ep = et ;
				GetTextExtentPoint32(hdc, dayt, strlen(dayt), &s) ;
				TextOut(hdc, xp - s.cx / 2, yp - s.cy, dayt, strlen(dayt)) ;
			}

			// mark the closing epoch of the Grand Period
			if (gr == Als.nGrps)
			{
				xp = Fr.left +  (int)((double)wd * (AstEp2 - epL) / pgint) ;
				DrawIcon(hdc, xp - 32, yp - 32, icEnd) ;
				et = ep ;
				ep = AstEp2 ; civildate() ;
				ep = et ;
				GetTextExtentPoint32(hdc, dayt, strlen(dayt), &s) ;
				TextOut(hdc, xp - s.cx / 2, yp + s.cy, dayt, strlen(dayt)) ;
			}

			if (ilpix > s.cy)
			for (e = floor(epL) ; e <= ceil(epR) ; e++) // calendar-day ticks
			{
				if (e >= epL && e <= epR)
				{ int t ;
						et = ep ;
						ep = e ; civildate() ;
						ep = et ;
					oPen = SelectObject(hdc, grayPen) ;
					  xp = Fr.left +  (int)((double)wd * (e - epL) / pgint) ;
					MoveToEx(hdc, xp, yp + 1, NULL) ;
					t = (day == 1) ? 8 : 2 ;	// elongate month start ticks
					  LineTo(hdc, xp, yp - t) ;
					SelectObject(hdc, oPen) ;

				if (wantDayLabels)
					{
						_itoa(day, str, 10) ;
						SetTextColor(hdc, RGB(192, 192, 192)) ;
						GetTextExtentPoint32(hdc, str, strlen(str), &s) ;
						TextOut(hdc, xp - s.cx / 2, yp + 2, str, strlen(str)) ;
						if (day == 1)	// it is the start of a month
						{				// show short month name, and year
						  sprintf(str, "%s %4.4d", szMonth[mo], yr) ;
						  TextOut(hdc, xp - s.cx / 2, yp + s.cy + 2, str, strlen(str)) ;
						}
						SetTextColor(hdc, RGB(0,0,0)) ;
					}
				}
			}

		if (RastRawDips)
		{
			for ( i = 0 ; i < Samp.nDips ; i++)
				if ((e = Samp.DipEps[i] + leadlag) >= epL && e <= epR)
				{
				    xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
					DrawIcon(hdc, xp - 15, yp - 31, icDipRaw) ;
					SetRect(&rcRastRawDip[i], xp - 4, yp - 4, xp + 4, yp + 4) ;
				}
		}
		
		if (RastMeanDips)
		{
			for ( i = 0 ; i < Samp.nmDips ; i++)
				if ((e = Samp.mDipEps[i] + leadlag) >= epL && e <= epR)
				{
				    xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
					DrawIcon(hdc, xp - 15, yp - 31, icDipMean) ;
					SetRect(&rcRastMeanDip[i], xp - 4, yp - 4, xp + 4, yp + 4) ;
				}
		}

		if (RastRawPeaks)
		{
			for ( i = 0 ; i < Samp.nPeaks ; i++)
				if ((e = Samp.PeakEps[i] + leadlag) >= epL && e <= epR)
				{
				    xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
					DrawIcon(hdc, xp - 15, yp, icPeakRaw) ;
					SetRect(&rcRastRawPeak[i], xp - 4, yp - 4, xp + 4, yp + 4) ;
				}
		}

		if (RastMeanPeaks)
		{
			for ( i = 0 ; i < Samp.nmPeaks ; i++)
				if ((e = Samp.mPeakEps[i] + leadlag) >= epL && e <= epR)
				{
				    xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
					DrawIcon(hdc, xp - 15, yp, icPeakMean) ;
					SetRect(&rcRastMeanPeak[i], xp - 4, yp - 4, xp + 4, yp + 4) ;
				}
		}

		if (RastTunedRawDips)
		{
			for ( i = 0 ; i < Samp.ntDips ; i++)
				if ((e = Samp.tDipEps[i] + leadlag) >= epL && e <= epR)
				{
				    xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
					DrawIcon(hdc, xp - 15, yp - 31, ictDipRaw) ;
					SetRect(&rcRastTunedRawDip[i], xp - 4, yp - 4, xp + 4, yp + 4) ;
				}
		}

		if (RastTunedMeanDips)
		{
			for ( i = 0 ; i < Samp.nmtDips ; i++)
				if ((e = Samp.tmDipEps[i] + leadlag) >= epL && e <= epR)
				{
				    xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
					DrawIcon(hdc, xp - 15, yp - 31, ictDipMean) ;
					SetRect(&rcRastTunedMeanDip[i], xp - 4, yp - 4, xp + 4, yp + 4) ;
				}
		}

		if (RastTunedRawPeaks)
		{
			for ( i = 0 ; i < Samp.ntPeaks ; i++)
				if ((e = Samp.tPeakEps[i] + leadlag) >= epL && e <= epR)
				{
				    xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
					DrawIcon(hdc, xp - 15, yp, ictPeakRaw) ;
					SetRect(&rcRastTunedRawPeak[i], xp - 4, yp - 4, xp + 4, yp + 4) ;
				}
		}

		if (RastTunedMeanPeaks)
		{
			for ( i = 0 ; i < Samp.nmtPeaks ; i++)
				if ((e = Samp.tmPeakEps[i] + leadlag) >= epL && e <= epR)
				{
				    xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
					DrawIcon(hdc, xp - 15, yp, ictPeakMean) ;
					SetRect(&rcRastTunedMeanPeak[i], xp - 4, yp - 4, xp + 4, yp + 4) ;
				}
		}

		if (wantModanom && _is.modAlignsExist) // display modified alignment dates
		{
			int bod ;
			HPEN oP ;
			HBRUSH br, oB ;
			LOGBRUSH lb;
			lb.lbStyle = BS_SOLID;

			for (bod = MER ; bod <= SUN ; bod++)
			{
				if (!RastBodyList[bod]) continue ;
			for ( i = 0 ; i <= align->found ; i++)
				{
				 double r[5] ;
				 switch(bod)
				 {
				 case SUN: lb.lbColor = RGB(192,192,  0) ; break ;	// gold
				 case MER: lb.lbColor = RGB(255,128, 64) ; break ;	// orange
				 case VEN: lb.lbColor = RGB(  0,192,  0) ; break ;	// green
				 case MAR: lb.lbColor = RGB(255,100,100) ; break ;	// light red
				 case JUP: lb.lbColor = RGB(200,200,200) ; break ;	// mid gray
				 case SAT: lb.lbColor = RGB(100,100,255) ; break ;	// light blue
				 case URA: lb.lbColor = RGB(  0,  0,255) ; break ;	// blue
				 case NEP: lb.lbColor = RGB(255,  0,255) ; break ;	// purple
				 }
				     br = CreateBrushIndirect(&lb) ;
				 if ((e = PredShift(bod, i, r)) >= epL && e <= epR)
					{
					 oP = SelectObject(hdc, blackPen) ;
					 oB = SelectObject(hdc, br) ;
							xp = Fr.left + (int)((double)wd * (e - epL) / pgint) ;
						    DrawCross(hWnd, 0, xp, yp,  8,  blackPen) ;
							Ellipse(hdc, xp - 4, yp - 4, xp + 4, yp + 4) ;
						    SelectObject(hdc, oP) ; 
						    SelectObject(hdc, oB) ;
					}
					 DeleteObject(br) ;
				}
			}
		}
				//xp = Fr.left + (int)((double)wd * Als.clusterepoch[gr]/pgint) ;
				//Ellipse(hdc, xp - 6, yp - 6, xp + 6, yp + 6) ;

		// for all the alignments in the group
		for (a = 0L ; a <= Als.nGr[gr] ; a++)
		{
		if (!RastBodyList[B = Als.Body[gr][a]]) continue ; // skip if not in body list

				switch (B) // icons and pens for bodies
				{
				case SUN: ico = icSun ;	pen = goldPen ;    break ;
				case MER: ico = icMer ;	pen = orangePen ;  break ;
				case VEN: ico = icVen ;	pen = greenPen ;   break ;
				case MAR: ico = icMar ;	pen = redPen ;     break ;
				case JUP: ico = icJup ;	pen = mdgrayPen ;  break ;
				case SAT: ico = icSat ;	pen = ltbluePen ;  break ;
				case URA: ico = icUra ;	pen = bluePen ;    break ;
				case NEP: ico = icNep ;	pen = purplePen ;  break ;
				}

				oPen = SelectObject(hdc, pen) ;

			// indicate the epochs of the alignments in the current group

				xp = Fr.left + (int)((double)wd * (Als.alnint[gr][a] = Als.Aep[gr][a] - epL) / pgint) ;

			// circle if on first lunar orbital leg (perigee to apogee)
				if (Als.Axtyp[gr]) Ellipse(hdc, xp - 4, yp - 4, xp + 4, yp + 4) ;
			// cross on either leg
				DrawCross(hWnd, 0, xp, yp, 6, pen) ;
				SetRect(&rcRastAl[Als.Sidx[gr][a]], xp - 4, yp - 4, xp + 4, yp + 4) ;

			if (wantIcons) DrawIcon(hdc,  xp - 4, yp - 18, ico) ;

			if (wantJoins)
			{
			//
			//	How do I deal with this?
			//
			// Perhaps I can simply say:----
			// if the current and previous raster lines each have exactly
			// one alignment for a given body, join the markers.

				if (gr > 0)
				{
					if ((Als.inGrp[gr-1][B] == 1) && (Als.inGrp[gr][B] == 1))
					{
								int oxp, oyp, nig, nis ;
							 double Aep, Sep ;

						nig =   Als.Bplc[gr-1][B] ;					// index in the group of body B
					    nis =   Als.Sidx[gr-1][nig] ;				// index of the alignment with B in the series
						Aep = Als.Alepof[nis] ;						// epoch of alignment with B in previous group
						Sep = Als.grEpAx[gr-1] - 13.777275 ;		// start ep of previous group 

						oxp = Fr.left + (int)((double)wd * (Aep - Sep) / pgint) ;
						oyp = Fr.top  + ht * (gr - 1) / Als.nGrps ;
							MoveToEx(hdc, oxp, oyp, NULL) ;
							  LineTo(hdc,  xp,  yp) ;
					}
				}
			}
		}
	}
			SelectObject(hdc, oPen) ;
			SelectObject(hdc, oBr) ;
			//DeleteObject(hbr) ;
			EndPaint(hWnd, &ps) ;
		  break ;

      default:                  // Passes it on if unprocessed
          return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return ((long)NULL);
}

#include "Viewer.h"

// **************************************************************
//                   General Graphing Window
// **************************************************************
long CALLBACK GraphProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    PAINTSTRUCT ps ;
	       SIZE sz ;
	        HDC hdc, hmemDC ;
		  HFONT oFnt ;
		   HPEN oPen ;
	    HBITMAP	bmGoDown, bmGoRight, bmToBase, bmToTip, oBm ;
		  POINT client ;
		 double topXo, botXo, topYo, botYo, topiL, botiL ;
		 double xmul, ymul, dymul ;
		 double L, c, u, yhi, ylo ; 
		    int i, k, xlen, gLeft, gTop, gRight, gBottom, xp, yp ;
			int dLeft, dTop, dRight, dBottom ;
			int xp1, yp1, xp2, yp2 ;
			int plotminor ;
		 double minor, major, fnt_ht ;
		 double lomaj, himaj ;
		   char buff[20], buffer[100] ;

   switch (message)
    {
	  case WM_COMMAND:
		  switch(LOWORD(wParam))
		  {
		   case WM_MOUSEGONE:
		       if (CurrentTip != NULL)
			   RemoveTip() ;
		       return 0L ;

		    default: break ;
		  }
		  break ; // end WM_COMMAND

      case WM_NCHITTEST: // works for a mouse event anywhere in this window

	// If the mouse has moved window, tell the abandoned window so that
	// it can turn off any tip that it might have showing, then make
	// this window officially current. Else preserve status quo.

	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

      case WM_MOUSEMOVE:
		  {
			  static w, h, x, y, ox, oy ;
			  static OldPicked, Icon1Drawn ;

		  client.x = LOWORD(lParam) ;
		  client.y = HIWORD(lParam) ;

		  // Put arrow-indicator on the level-button
		  // corresponding to the Null Profile data-point
		  // under the mouse cursor.
		  for ( i = 1, LevelPicked = 0 ; i <= Levels ; i++ )
		  {
		    if (PtInRect(&rcNull[i], client))
			{
				LevelPicked = i ;
			    break ;			   // drop out at first find.
			}
		  }

		  ivrc(hWndBud, &rccolrt, TRUE) ;

		  // In the Results Window, put arrow-indicator on the
		  // bud height corresponding to the Null Profile
		  // data-point under the mouse cursor.

		  // Before an arrow icon is displayed, a patch of
		  // the image at the arrow's destination is first grabbed
		  // and stored.  If the arrow must "move", or vanish, the
		  // patch is replaced, obliterating the icon.

			if (LevelPicked != OldPicked)
			{
				HDC hDC ;

				    x = rcmidpt[i].left + 4 ;
				    y = rcmidpt[i].top  + 4 ;

				    w = h = 32 ;				    // width and height of patch

				  if (hPatch3 != NULL)				               // if grabbed patch exists
				  {
					  hPatch3 = PutPatch(hWndRslt, hPatch3, w, h, ox, oy) ; // replace it, so wiping the icon
					  Icon1Drawn = 0 ;
				  }

				  hPatch3 = GrabPatch(hWndRslt, w, h, x + 3, y + 3) ; // grab a new patch

				   ox = x + 3 ; oy = y + 3 ;				       // record place for restoration

				   hDC = GetDC(hWndRslt) ;
				   DrawIcon(hDC, x + 3, y + 3, icoPtr) ;		   // draw the arrow-icon on top
				   Icon1Drawn = 1 ;
				   ReleaseDC(hWndRslt, hDC) ;


			} // end if (LevelPicked != OldPicked)
			else
				if(LevelPicked == 0) // no level picked out - remove arrow if drawn
			{
				if (hPatch3 && Icon1Drawn)
				{
					  hPatch3 = PutPatch(hWndRslt, hPatch3, w, h, ox, oy) ; // replace patch, so wiping the icon
					  Icon1Drawn = 0 ;							   
				}
			}

 			OldPicked = LevelPicked ;
		  }
		  break ;

	  case WM_RBUTTONUP:

		// Respond to mouse-driven exclusions/inclusions
		// on the Null Profile graph

		 if (AllDone)  // but don't bother if measurements missing
		 {
		  client.x = LOWORD(lParam) ;			// mouse is where?
		  client.y = HIWORD(lParam) ;

		   for (i = 1 ; i <= Levels ; i++)
		   {
			  if (PtInRect(&rcNull[i], client))	// if mouse in data point
			  {
			   IncludeLev[i] ^= 1 ;				// toggle point's inclusion state

			   Lambda(LEFT) ;					// re-compute Lambdas
			   Lambda(RIGHT) ;
			   Lambda(BOTH) ;

			   RecordLambdas() ;				// keep 'em

			   ivrc(hWnd,     NULL, TRUE) ;	// update displays
			   ivrc(hWndBud,  NULL, TRUE) ;
			   ivrc(hWndRslt, NULL, TRUE) ;
			  }
		   }
		   return 0 ;
		 }
		  break ;

	  case WM_MOVE:
	  case WM_SIZE:
	  case WM_WINDOWPOSCHANGED:
		  ivrc(hWnd, NULL, TRUE) ;
		  return 0 ;
		  break ;

	  case WM_PAINT:
		  hdc = BeginPaint(hWnd, &ps) ;
		  oPen = SelectObject(hdc, whitePen) ;
		  hmemDC = CreateCompatibleDC(hdc) ;
		  bmGoDown  = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_GO_DOWN)) ;
		  bmGoRight = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_GO_RIGHT)) ;
		  bmToBase  = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TO_BUDBASE)) ;
		  bmToTip   = LoadBitmap(hInst, MAKEINTRESOURCE(IDB_TO_BUDTIP)) ;
		  
		  GetClientRect(hWnd, &rcgraf) ;

		  Rectangle(
			  hdc,
			  gLeft   = rcgraf.left   + 40,
			  gTop    = rcgraf.top    + 45,
			  gRight  = rcgraf.right  - 10,
			 (gBottom = rcgraf.bottom - (rcgraf.bottom - rcgraf.top) / 2) + 1
			  ) ;

		  Rectangle(
			  hdc,
			  dLeft   = gLeft,
			  dTop    = gBottom + 40,
			  dRight  = gRight,
			 (dBottom = rcgraf.bottom - 25) + 1
			  ) ;

		if (AllDone)
		{
		  oFnt = SelectObject(hdc, hfnt) ;
		  SetBkMode(hdc, TRANSPARENT) ;

		      if (DIA) sprintf(buffer," On Diameters."  ) ; 
			  if (LEF) sprintf(buffer," On Left Radii." ) ;
			  if (RYT) sprintf(buffer," On Right Radii.") ;

			  TextOut( hdc,
				       rcgraf.left + 4,
					   rcgraf.top  + 2,
					   buffer,
					   strlen(buffer)) ;

			  GetTextExtentPoint32
			  ( hdc,
			    buffer,
				strlen(buffer),
				&sz ) ;

			    xlen = sz.cx ;

			for ( k = 0 ; k < 2 ; k++)
			{
			  if (!k)
			  {
		      if (DIA) sprintf(buffer,"Pr. Lambda %5.3f  MRD %4.2f%% Std.Err. %4.2f%%",
				                      pBudResults->DiamProjLambda,
				                      pBudResults->DiamProjMRD,
									  DProjSD) ; 
			  if (LEF) sprintf(buffer,"Pr. Lambda %5.3f  MRD %4.2f%% Std.Err. %4.2f%%",
				                      pBudResults->LeftProjLambda,
				                      pBudResults->LeftProjMRD,
									  LProjSD) ;
			  if (RYT) sprintf(buffer,"Pr. Lambda %5.3f  MRD %4.2f%% Std.Err. %4.2f%%",
				                      pBudResults->RightProjLambda,
									  pBudResults->RightProjMRD,
									  RProjSD) ;

			    SetTextColor(hdc, RGB(255,0,0)) ;

			    TextOut(hdc,
					    rcgraf.left + xlen + 10,
						rcgraf.top + 2,
						buffer,
						strlen(buffer)) ;
			  }
			  else
			  {
		      if (DIA) sprintf(buffer,"Rg. Lambda %5.3f  MRD %4.2f%% Std.Err. %4.2f%%",
				                      pBudResults->DiamRegrLambda,
				                      pBudResults->DiamRegrMRD,
									  DRegrSD) ; 
			  if (LEF) sprintf(buffer,"Rg. Lambda %5.3f  MRD %4.2f%% Std.Err. %4.2f%%",
				                      pBudResults->LeftRegrLambda,
				                      pBudResults->LeftRegrMRD,
									  LRegrSD) ;
			  if (RYT) sprintf(buffer,"Rg. Lambda %5.3f  MRD %4.2f%% Std.Err. %4.2f%%",
				                      pBudResults->RightRegrLambda,
									  pBudResults->RightRegrMRD,
									  RRegrSD) ;

			    SetTextColor(hdc, RGB(0,0,255)) ;

			    TextOut(hdc,
					    rcgraf.left + xlen + 10,
						rcgraf.top + 4 + sz.cy,
						buffer,
						strlen(buffer)) ;
			  }
			}

	//title
		  SelectObject(hdc, hfnt) ;
		  SetTextColor(hdc, RGB(0, 0, 0)) ;
		  strcpy(buff, "Null Profile") ;
		  GetTextExtentPoint32
			     ( hdc,
			       buff,
				   strlen(buff),
				   &sz ) ;

		  TextOut(hdc,
			     (gRight + gLeft) / 2 - sz.cx/2,
				  gTop - (sz.cy + 2),
				  buff, strlen(buff)) ;

		  SelectObject(hdc, hfnt1) ;

    //scaling and framing
		  topXo =  ceil(hiXo * 10.0) / 10.0 ;
		  botXo = floor(loXo * 10.0) / 10.0 ;
		  topYo =  ceil(hiYo * 10.0) / 10.0 ;
		  botYo = floor(loYo * 10.0) / 10.0 ;

		   xmul = (double)(gRight  - gLeft)/(topXo - botXo) ; // pixels per unit
		   ymul = (double)(gBottom - gTop )/(topYo - botYo) ; // pixels per unit

		  SetTextAlign(hdc, TA_TOP) ;
		  SetBkMode(hdc, TRANSPARENT) ;

	// y ticks and grid
		  for ( u = botYo ; u <= topYo + 0.1 ; u += 0.1 ) 
		  {
			  //yp = (int)(ymul * (topYo - u)) + gTop ;
			  yp = (int)(ymul * (u - botYo)) + gTop ;

			if ( yp <= gBottom )
			{
			  SelectObject(hdc, blackPen) ;

			  xp = gLeft - 3 ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			  xp = gLeft ;
				  LineTo(hdc, xp, yp) ;

			  SelectObject(hdc, palePen) ;

			  xp = gLeft ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			  xp = gRight ;
				  LineTo(hdc, xp, yp) ;
			}
		  }

	// y notation
		  for ( u = botYo ; u <= topYo + 0.2 ; u += 0.2 ) 
		  {
			  //yp = (int)(ymul * (topYo - u)) + gTop ;
			  yp = (int)(ymul * (u - botYo)) + gTop ;

			if ( yp <= gBottom )
			{
			  if (u == -0.0) u = 0.0 ;
		      sprintf(buff,"%2.1f",u) ;
		      GetTextExtentPoint32
			     ( hdc,
			       buff,
				   strlen(buff),
				   &sz ) ;
		  
		     TextOut(hdc, gLeft - (sz.cx + 5), yp - sz.cy/2,buff,strlen(buff)) ;
			}
		  }

   // Yo legend
		  {
			  int h, len ;
		  sprintf(buff,"Yo") ;
		  GetTextExtentPoint32
			 ( hdc,
			   buff,
			   len = strlen(buff),
			   &sz ) ;
		  TextOut(hdc, 1 ,h = (gBottom + gTop) / 2 - sz.cy/2, buff, len) ;
		  oBm = SelectObject(hmemDC, bmGoDown) ;
		  BitBlt(hdc, 1 + sz.cx / 2 - 2, h + sz.cy + 5, 5, 17,
			     hmemDC, 0, 0, SRCCOPY) ; 
		  }

   // x ticks, graticule and notation
		  for ( u = botXo ; u <= topXo + 0.1 ; u += 0.1 )
		  {
			  xp = (int)( xmul * (u - botXo)) + gLeft ;
			  if (xp <= gRight)
			  {
			   SelectObject(hdc, blackPen) ;

			  yp = gBottom + 3 ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			  yp = gBottom ;
				  LineTo(hdc, xp, yp) ;

		  if (u == -0.0) u = 0.0 ;
		  sprintf(buff,"%2.1f",u) ;

		  GetTextExtentPoint32
			  ( hdc,
			    buff,
				strlen(buff),
				&sz ) ;
		  
		  TextOut(hdc, xp - sz.cx/2, yp + 5,buff,strlen(buff)) ;

			  SelectObject(hdc, palePen) ;

			  yp = gBottom ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			  yp = gTop ;
				  LineTo(hdc, xp, yp) ;

			  }
		  }

  // Xo legend
		  {
			  int a, d ;
		  sprintf(buff,"Xo") ;
		  GetTextExtentPoint32
			  ( hdc,
			    buff,
				strlen(buff),
				&sz ) ;
		  TextOut(hdc,
			      a = (gRight + gLeft) / 2,
				  d = gBottom + sz.cy + 4,
				  buff, strlen(buff)) ;

		   oBm = SelectObject(hmemDC, bmGoRight) ;
		   BitBlt(hdc, a + sz.cx / 2 + 8, d + sz.cy / 2 - 3, 15, 7,
			      hmemDC, 0, 0, SRCCOPY) ;
		  }

  // orientation indicators
		  oBm = SelectObject(hmemDC, bmToBase) ;
		  BitBlt(hdc, gLeft + 2, gBottom + sz.cy + 4, 32, 8,
			     hmemDC, 0, 0, SRCCOPY) ;

		  oBm = SelectObject(hmemDC, bmToTip) ;
		  BitBlt(hdc, gRight - 24, gBottom + sz.cy + 4, 22, 10,
			     hmemDC, 0, 0, SRCCOPY) ;

	// the actual plot

			  SelectObject(hdc, redPen) ;

		  for ( i = 1 ; i <= Levels ; i++ )
		  {
			  xp = (int)(xmul * (Xo[i] - botXo)) + gLeft ;

			//yp = (int)(ymul * (topYo - Yo[i])) + gTop ;
			  yp = (int)(ymul * (Yo[i] - botYo)) + gTop ;

		// join data points
			  if ( i == 1 )
				  MoveToEx(hdc, xp, yp, NULL) ;
				  else
				  LineTo(hdc, xp, yp) ;

		// cross at data point
			  DrawCross(hWnd, invert, xp, yp, 2, redPen) ;

			 // sprintf(buff, "(%2.2f, %2.2f)", Xo[i], Yo[i]) ;
			 // TextOut(hdc, xp + 8, yp - 8, buff, strlen(buff)) ;
			  
		// create invisible 4x4 rectangles centred on the data points
		// for mouse pointing

			  SetRect(&rcNull[i], xp - 2, yp - 2, xp + 2, yp + 2) ;
		  }

		// indicate data points excluded from lambda computation

		  for ( i = 1 ; i <= Levels ; i++ )
		  {
			  if (!IncludeLev[i])
			  {
			   xp = (int)(xmul * (Xo[i] - botXo)) + gLeft ;

			   //yp = (int)(ymul * (topYo - Yo[i])) + gTop ;
			   yp = (int)(ymul * (Yo[i] - botYo)) + gTop ;

				  Ellipse(hdc, xp - 4, yp - 4, xp + 4, yp + 4) ;
			  }

		  }

	   // draw best-fit straight lines through the data points of
	   // the levels giving best fit: clip the lines at plot borders
	   // if necessary.

		for ( k = 0 ; k < 2 ; k++)
		{
			int b_lev ;	 // best level

		 if (!k)
		 {
		  if (DIA) {
			            L = -pBudResults->DiamProjLambda ;
					b_lev =  pBudResults->BProjBestAt ;
		           }
		  if (LEF) {
			            L = -pBudResults->LeftProjLambda ;
					b_lev =  pBudResults->LProjBestAt ;
		           }
		  if (RYT) {
			            L = -pBudResults->RightProjLambda ;
					b_lev =  pBudResults->RProjBestAt ;
		           }

		  c = Yo[b_lev] - L * Xo[b_lev] ; // intercept
		  SelectObject(hdc, redPen) ;
		 }
		 else
		 {
		  if (DIA) { 
			            L = -pBudResults->DiamRegrLambda ;
					b_lev =  pBudResults->BRegrBestAt ;
		           }
		  if (LEF) {
			            L = -pBudResults->LeftRegrLambda ;
					b_lev =  pBudResults->LRegrBestAt ;
		           }
		  if (RYT) {
			            L = -pBudResults->RightRegrLambda ;
					b_lev =  pBudResults->RRegrBestAt ;
		           }

		  c = Yo[b_lev] - L * Xo[b_lev] ; // intercept
		  SelectObject(hdc, bluePen) ;
		 }

		yhi = L * Xo[1] + c ;
		ylo = L * Xo[Levels] + c ;

		  if ( yhi > topYo)
		  {
		  xp1 = (int)(xmul * ((topYo - c) / L - botXo)) + gLeft ;
		  yp1 = gBottom ;
		  }
		  else
		  {
		  xp1 = (int)(xmul * (Xo[1] - botXo)) + gLeft ;
		  //yp1 = (int)(ymul * (topYo -   yhi)) + gTop ;
		  yp1 = (int)(ymul * (yhi - botYo)) + gTop ;
		  }

		  if ( ylo < botYo)
		  {
		  xp2 = (int)(xmul * ((botYo - c) / L - botXo)) + gLeft ;
		  yp2 = gTop ;
		  }
		  else
		  {
		  xp2 = (int)(xmul * (Xo[Levels] - botXo) + gLeft) ;
		  //yp2 = (int)(ymul * (topYo - ylo)) + gTop ;
		  yp2 = (int)(ymul * (ylo - botYo)) + gTop ;
		  }

		  MoveToEx(hdc, xp1, yp1, NULL) ;
		    LineTo(hdc, xp2, yp2) ;
		}

		 // Axes

		  SelectObject(hdc, blackPen) ;
		  xp = (int)(xmul * (0.0 - botXo) + gLeft) ; 
		  yp = gTop ;
		  MoveToEx( hdc, xp, yp, NULL ) ;
		  yp = gBottom ;
		  LineTo(hdc, xp, yp) ;

		  xp = gLeft ;
		  yp = (int)(ymul * (0.0 - botYo)) + gTop ;
		  MoveToEx(hdc, xp, yp, NULL) ;
		  xp = gRight ;
		  LineTo(hdc, xp, yp) ;
		}

  // differential, inter-level lambda stuff

  // title

          sprintf(buff,"Inter-Level ") ;
		  SelectObject(hdc, hfnt) ;
 		  GetTextExtentPoint32
			     ( hdc,
			       buff,
				   strlen(buff),
				   &sz ) ;

		  TextOut(hdc,
			     (dRight + dLeft) / 2 - sz.cx/2,
				  dTop - (sz.cy + 2),
				  buff, strlen(buff)) ;

		  SelectObject(hdc, hgrk) ;
		  strcpy(buff,"l") ;

		  TextOut(hdc,
			     (dRight + dLeft) / 2 + sz.cx/2,
				  dTop - (sz.cy + 2),
				  buff, strlen(buff)) ;

  // lambda legend
		  TextOut(hdc, 1, (dTop + dBottom)/2, buff, 1) ;

		  SelectObject(hdc, hfnt1) ;

		 // take top of chart such that the highest value to plot lies
		 // inside the topmost tenth-of-unit chart interval. 

		 topiL =  ceil(hiiL * 10.0) / 10.0 ; // highest plottable lambda value

		 // but limit the chart if the range is too great

		 if (topiL > 5.0) topiL = 5.0 ;

		 // take bottom of chart such that the lowest value to plot
		 // lies inside the bottommost tenth-of-unit chart interval.
		 
		 botiL = floor(loiL * 10.0) / 10.0 ; //  lowest plottable lambda value

		 // but limit the chart if the range is too great

		 if (botiL < -3.0) botiL = -3.0 ;

		 //  pixels per unit = dymul =
		 // (display range in pixels)/(plottable value range)

		 dymul = (double)(dBottom - dTop )/(topiL - botiL) ; 

	     lomaj =  ceil(botiL) ; // value at lowest major tick
	     himaj = floor(topiL) ; // value at highest major tick
		 major = 1.0 ;

		 // find the least number of unit divisions yielding
		 // a chart tick interval larger than the font height.

		 while (dymul * major < (double)sz.cy) major++ ; // de-clutter

 		 plotminor = 1 ;				 // assume we will be plotting minor.

		    fnt_ht = (double)(sz.cy/2) ; // guage against half font height.

             minor = 0.1 ;				 // try for tenths first.

	     // try each minor division in turn.
		 if (dymul * minor < fnt_ht )
			 minor = 0.2 ; // one tenth is too small, will two tenths do?

		 if (dymul * minor < fnt_ht ) 
			 minor = 0.5 ; // two tenths is too small, will halves do?

		 if (dymul * minor < fnt_ht ) 
			 plotminor = 0 ; // OK, even halves are too small, don't plot any.

  // minor y ticks and grid

		 if (plotminor)
		 {
			  SelectObject(hdc, palePen) ;

		  for ( u = lomaj - 1.0 ; u <= himaj + 1.0 ; u += minor ) 
		  {
			  yp = (int)(dymul * (topiL - u)) + dTop ;

			if (yp >= dTop && yp <= dBottom) // draw only if on-plot
			{
			  xp = dLeft - 3 ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			  xp = dRight ;
				  LineTo(hdc, xp, yp) ;
			}
		  }
		 }

	// y notation

			  yp = dTop ;

			//if ( yp >= dTop )
			{
		      sprintf(buff,"(%2.1f)", topiL ) ;
		      GetTextExtentPoint32
			     ( hdc,
			       buff,
				   strlen(buff),
				   &sz ) ;
		  
		     TextOut(hdc, 1, yp - 3*sz.cy/2, buff, strlen(buff)) ;
			}
  
			  yp = (int)(dymul * (topiL - botiL)) + dTop ;

			//if ( yp >= dTop )
			{
		      sprintf(buff,"(%2.1f)", botiL ) ;
		      GetTextExtentPoint32
			     ( hdc,
			       buff,
				   strlen(buff),
				   &sz ) ;
		  
		     TextOut(hdc, 1, yp + sz.cy/2, buff, strlen(buff)) ;
			}
  
		  for ( u = lomaj ; u <= himaj ; u += major ) 
		  {
			  yp = (int)(dymul * (topiL - u)) + dTop ;

			if ( yp >= dTop )
			{
		      sprintf(buff,"%2.1f",u) ;
		      GetTextExtentPoint32
			     ( hdc,
			       buff,
				   strlen(buff),
				   &sz ) ;
		  
		     TextOut(hdc, dLeft - (sz.cx + 5), yp - sz.cy/2, buff, strlen(buff)) ;
			}
		  }

	// y ticks and grid lines

		  for ( u = lomaj ; u <= himaj ; u += 1.0 ) 
		   {
			  yp = (int)(dymul * (topiL - u)) + dTop ;

			if (yp >= dTop)
			{
			 SelectObject(hdc, blackPen) ;
			 MoveToEx(hdc, dLeft - 3, yp, NULL) ;
			   LineTo(hdc, dLeft, yp) ;

			 if ( fabs(u) == 0.0)
			 SelectObject(hdc, blackPen) ;
			 else
			 SelectObject(hdc, grayPen) ;

			 MoveToEx(hdc, dLeft, yp, NULL) ;
			   LineTo(hdc, dRight, yp) ;
			}
		   }

   // x ticks, graticule and notation
		  for ( u = botXo ; u <= topXo + 0.1 ; u += 0.1 )
		  {
			  xp = (int)( xmul * (u - botXo)) + gLeft ;
			  if (xp <= gRight)
			  {
			   SelectObject(hdc, blackPen) ;

			   yp = dBottom + 3 ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			   yp = dBottom ;
				  LineTo(hdc, xp, yp) ;

		       sprintf(buff,"%2.1f",u) ;
		       GetTextExtentPoint32
			        ( hdc,
			          buff,
				      strlen(buff),
				      &sz ) ;
		  
		  TextOut(hdc, xp - sz.cx/2, yp + 5,buff,strlen(buff)) ;

			  if ( fabs(u) == 0.0 )
				  SelectObject(hdc, blackPen) ;
			  else
				  SelectObject(hdc, palePen) ;

			  yp = dBottom ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			  yp = dTop ;
				  LineTo(hdc, xp, yp) ;
			  }
		  }

		  {
			  static B, T ;	  // for brevity

			  B = dBottom ;
			  T = dTop ;

			  SelectObject(hdc, goldPen) ;

		  for ( i = 1 ; i < Levels ; i++ )
		  {
			double xn, yn ;
			static oxp, oyp, x1, y1, x2, y2, j ;
			static oldstate, newstate, Caseof ;

			//Case Old	  New	  Old  New
			//
			// 0 :    in->in        1, 1
			// 1 : above->in		3, 1
			// 2 : above->below		3, 2
			// 3 : below->below		2, 2
			// 4 : below->in		2, 1
			// 5 : below->above		2, 3
			// 6 : above->above		3, 3
			// 7 :    in->above		1, 3
			// 8 :    in->below		1, 2

			static Old[] = {1,3,3,2,2,2,3,1,1} ;   // L.U.T.
			static New[] = {1,1,2,2,1,3,3,3,2} ;
			static Sel[] = {0,1,2,3,4,5,6,7,8} ;

			  xn = (Xo[i] + Xo[i+1])/2.0 - botXo ;
			  yn = topiL - iL[i] ;

			  xp = (int)( xmul * xn) + gLeft ;
			  yp = (int)(dymul * yn) + dTop  ;

			  if (i == 1) { oxp = xp ; oyp = yp ; }

			  if (oyp < dTop) 
				  oldstate = 3 ;	// above
			  else
			  if (oyp > dBottom)
			      oldstate = 2 ;	// below
			  else
				  oldstate = 1 ;	// on chart


			  if (yp < dTop)
				  newstate = 3 ;	// above
			  else
			  if (yp  > dBottom)
			      newstate = 2 ;	// below
			  else
				  newstate = 1 ;	// on chart

		// Use Look Up Table
			  for (j = 0 ; j < 9 ; j++)
				  if (newstate == New[j] && oldstate == Old[j])
			      { 
				   Caseof = Sel[j] ;
				   break ;
			      }

			  switch (Caseof)			// nine possible cases
			  {
			  case 0: 				// 0 :    in->in        1, 1
					  x1 = oxp ; y1 = oyp ;
					  x2 =  xp ; y2 =  yp ; 
					  break ;
			  case 1:               // 1 : above->in		3, 1
				      x1 = (T - oyp)*(xp - oxp)/(yp - oyp) + oxp ;
					  y1 = T ;
					  x2 = xp ;
					  y2 = yp ;
					  break ;
			  case 2: 				// 2 : above->below		3, 2
				      x1 = (T - oyp)*(xp - oxp)/(yp - oyp) + oxp ;
					  y1 = T ;
				      x2 = (B - oyp)*(xp - oxp)/(yp - oyp) + oxp ;
					  y2 = B;
					  break ;
			  case 3: 				// 3 : below->below		2, 2
				      goto skipit ;	
					  break ;
			  case 4:				// 4 : below->in		2, 1
					  x1 = (oyp - B)*(xp - oxp)/(oyp - yp) + oxp ;
					  y1 = B ;
					  x2 = xp ;
					  y2 = yp ;
				      break ;
			  case 5:				// 5 : below->above		2, 3
					  x1 = (oyp - B)*(xp - oxp)/(oyp - yp) + oxp ;
					  y1 = B;
					  x2 = (oyp - T)*(xp - oxp)/(oyp - yp) + oxp ;
					  y2 = T ;
				      break ;
			  case 6:				// 6 : above->above		3, 3
				      goto skipit ;	
					  break ;
			  case 7: 				// 7 :    in->above		1, 3
				      x1 = oxp ;
					  y1 = oyp ;
					  x2 = (oyp - T)*(xp - oxp)/(oyp - yp) + oxp ;
					  y2 = T ;
				      break ;
			  case 8:				// 8 :    in->below		1, 2
				      x1 = oxp ;
					  x2 = oyp ;
				      x2 = (B - oyp)*(xp - oxp)/(yp - oyp) + oxp ;
					  y2 = B ;
				      break ;
			  }

		// join data points
				  MoveToEx(hdc, x1, y1, NULL) ;
				    LineTo(hdc, x2, y2) ;

		// cross at data point
			if (yp >= dTop && yp <= dBottom)
			  DrawCross(hWnd, invert, xp, yp, 2, redPen) ;

skipit:		oxp = xp ;
			oyp = yp ; 
		  }
        }

		for ( k = 0 ; k < 2 ; k++) // draw lines for the general lambdas
		{
		 if (!k)
		 {
		  if (DIA) L = pBudResults->DiamProjLambda ;
		  if (LEF) L = pBudResults->LeftProjLambda ;
		  if (RYT) L = pBudResults->RightProjLambda ;

		  SelectObject(hdc, redPen) ;
		  yp = (int)(dymul * (topiL - L)) + dTop ;
		      xp = dLeft ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			  xp = dRight ;
				  LineTo(hdc, xp, yp) ;
		 }
		 else
		 {
		  if (DIA) L = pBudResults->DiamRegrLambda ;
		  if (LEF) L = pBudResults->LeftRegrLambda ;
		  if (RYT) L = pBudResults->RightRegrLambda ;

		  SelectObject(hdc, bluePen) ;
			  yp = (int)(dymul * (topiL - L)) + dTop ;
		      xp = dLeft ;
				  MoveToEx(hdc, xp, yp, NULL) ;
			  xp = dRight ;
				  LineTo(hdc, xp, yp) ;
		  }
		 }

		  SelectObject(hdc, oFnt) ;
		  SelectObject(hdc, oPen) ;
		  SelectObject(hmemDC, oBm) ;
		  DeleteDC(hmemDC) ;
		  DeleteObject(bmGoDown) ;
		  DeleteObject(bmGoRight) ;
		  DeleteObject(bmToBase) ;
		  DeleteObject(bmToTip) ;

		  EndPaint(hWnd, &ps) ;
		  break ; // end WM_PAINT


      default:                  /* Passes it on if unprocessed    */
          return (DefWindowProc(hWnd, message, wParam, lParam));
    }
    return ((long)NULL);
}

/*******************************************************************
			 ImageryProc(hWnd, message, wParam, lParam)

             Acquire, Save, Modify, Use or Print Image
			          Window Procedure
 *******************************************************************/
long CALLBACK ImageryProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
                  PAINTSTRUCT ps ;
static                    HDC hdc, hmemDC, hmemDCc, htemp ;
static				    HFONT ofnt ;
static				     HPEN oPen ;
static				   BITMAP bm ;
static				  HBITMAP  opBm, oBmc, hBm, oBm ;
static                   RECT rc, rcsel, rcinset, rcclip ;
static               BYTE FAR * lpBits ;
static   BITMAPINFOHEADER FAR * lpbmi ;
static                      int rot, rez, tstbud ;
static				     double aspect, cs, sn ;
static                   double fBrightChange = 0.0, fContrastChange = 0.0 ;
static                   double oldfBright = 0.0, oldfContrast = 0.0 ;
static                     char Extension[10] ;
static                     char buff[180] ;
// The following three pointers have been made global
// for general access, and are now declared in Bud32.h 
//static                     BYTE * pnewbuf ;
//static                     BYTE * pTemp ;
//static                     BYTE * pTmp ;
static						 BYTE * pBuf ;
static                     BOOL QR    = TRUE, swap = FALSE ;
static                     BOOL Aclkw = TRUE, Clkw = FALSE ;
static                  __int32 RotType ;
static                   UINT32 outw, outh, w, h, wd, ht, hnew, wnew ;
static                   UINT32 winset, hinset, k, temp ;
static                   UINT32 xad, yad, xbd, ybd ;
static                      int curinimage = 0 ;
static                      int changebricon = 0, changingbricon = 0 ;
static                    POINT pt, ptstart, ptprevend, ptnow, ptclip ;
static                    POINT cpt, cupt, tpt, box, pt_cap ;
static                     BOOL prev = FALSE ;
static					   BOOL success ;
static                      int xa, ya, xb, yb, nPos ;
static                      int selecting = 0, selected = 0, saved = 0 ;
static                      int OEX = 0, GRB = 0, USE = 0, ROT = 0, PMX = 0 ;
static                      int SLR = 0, CRP = 0, RSZ = 0, SAC = 0 ;
static                      int BRC = 0, PRN = 0, LAY = 0, TST = 0 ;

   switch (message)
    {
   case WM_COMMAND:

	   switch (LOWORD(wParam))
	   {
	   case WM_MOUSEGONE:
		   if (CurrentTip != NULL)
		   RemoveTip() ;
		   return 0L ;

	   case IDM_PICK_N_MIX:

		   break ;

	   case IDM_OPEN_EXISTING:

		   OEX = OpeninImagery = 1 ;
		   captured = 0 ;
			ivrc(hWnd, &rctl[Oex], TRUE) ;
			UpdateWindow(hWnd) ;

		   if (HaveImage && AskIfToSave) // if there is an image already
		   {
			   int UserSays ;

			   UserSays = MessageBox(NULL,
                                    "You have indicated that a New Image\n" \
                                    "should be loaded into Imagery.\n\n" \
                                    "Do you wish to Save the Current Image\n" \
                                    "Before loading the New Image into Imagery?\n\n" \
                                    "     ***** Please Note *****\n\n" \
                                    "Saving an Image DOES NOT update the\n" \
                                    "     Bud Workshop's Archive.\n\n" \
                                    "     Save the Current Image?\n",
                                    "Save Existing Image?",
									 MB_ICONQUESTION|MB_YESNO
									) ;

			   if (UserSays == IDYES)
				   SendMessage(hWnd, WM_COMMAND, IDM_SAVE_IMAGE, 0L) ;
		   }


		  // get the new file name
		  if (GetBudFile(hWnd) == TRUE)
		  {
		  // pick out the extension
		  strcpy( Extension, GetExt(DropPath(szImageryFile)) ) ;

		  if (!_stricmp(".BMP",Extension))	// Open a BMP
		  {

				HISSRC hSrc ;

			if (GlobalSize(hTempo)) GlobalFree(hTempo) ;
			if (GlobalSize(hTemp) ) GlobalFree(hTemp ) ;
			if (GlobalSize(newbuf)) GlobalFree(newbuf) ;

			   hSrc = _ISOpenFileSource( szImageryFile ) ;

			 newbuf = _ISReadBMP
						(
						hSrc,
						&w,
						&h,
						24,
						NULL
						) ;

			   _ISCloseSource(hSrc) ;

		   if (newbuf)
		   {
			   pnewbuf = (BYTE *) newbuf ;
			 HaveImage = 1 ;
			 Previewed = 0 ;
			  acquired = 0 ;
		 OpeninImagery = 0 ;
			   nBright = nContrast = 500 ;
			   fBright = fContrast = 0.0 ;
			       OEX = 0 ;
				 w_now = w ;
				 h_now = h ;
    		 ivrc(hWnd, NULL, TRUE) ;
		   }
		   else
		   {
			   HaveImage = 0 ;
		       selecting = 0 ;
			   selected  = 0 ;
			       w_now = h_now = 1 ;
		   }
		  }

		  if (!_stricmp(".JPG",Extension))  // Open a JPEG
		  {

			  HISSRC hSrc ;

			if (GlobalSize(hTempo)) GlobalFree(hTempo) ;
			if (GlobalSize(hTemp) ) GlobalFree(hTemp ) ;
			if (GlobalSize(newbuf)) GlobalFree(newbuf) ;

			   hSrc = _ISOpenFileSource( szImageryFile ) ;

			 newbuf = _ISReadJPG
						(
						hSrc,
						&w,
						&h,
						24
						) ;

			   _ISCloseSource(hSrc) ;

		   if (newbuf)
		   {
			   pnewbuf = (BYTE *) newbuf ;
			 HaveImage = 1 ;
			 Previewed = 0 ;
			  acquired = 0 ;
		 OpeninImagery = 0 ;
			     w_now = w ;
			     h_now = h ;
			       OEX = 0 ;
			   nBright = nContrast = 500 ;
			   fBright = fContrast = 0.0 ;
    		 ivrc(hWnd, NULL, TRUE) ;
		   }
		   else
		   {
			   HaveImage = 0 ;
			   selecting = 0 ;
			    selected = 0 ;
				   w_now = h_now = 1 ;
		   }
		   
		  }
	    }
		  else
		  {
		   OEX = 0 ;
			ivrc(hWnd, &rctl[Oex], TRUE) ;
			UpdateWindow(hWnd) ;
		  }
		   break ;

	   case IDM_SELECT_SOURCE:

		TWAIN_SelectImageSource(hWnd);

		   break ;

	   case IDM_ACQUIRE_IMAGE:

			GRB = 1 ;
			captured = 0 ;
			ivrc(hWnd, &rctl[Grb], TRUE) ;
			UpdateWindow(hWnd) ;

		        // free up current image and palette if any
				DiscardImage();
				 acquired = 0 ;
				selecting = 0 ;
			 	 selected = 0 ;
				HaveImage = 0 ;
				nBright = nContrast = 500 ;
				fBright = fContrast = 0.0 ; 
				// clear the window during/before Acquire dialog

				ivrc(hWndAcq, NULL, TRUE);

			// TWAIN operations	via EZTW32.DLL
            if (TWAIN_OpenDefaultSource())
			{
				   hDib = TWAIN_AcquireNative(hWndAcq, wPixTypes);
            }
				if (hDib)
				{
					acquired = 1 ;

				w = w_now = TWAIN_DibWidth(hDib);
				h = w_now = TWAIN_DibHeight(hDib);

		// get pointer to DIB info-header supplied by TWAIN

		        lpbmi = (LPBITMAPINFOHEADER)GlobalLock(hDib) ;

		// point to buffer: we assume 24 bit DIB (no colour table).

		if (lpbmi->biBitCount == 24)
			lpBits = (BYTE *)lpbmi + lpbmi->biSize ;
			else // is some other format
			{
				msgbox = 1 ;
			MessageBox(hWnd,"Problem with image resolution!!",
				            "Acquire..",
							MB_ICONEXCLAMATION|MB_OK) ;
			    msgbox = 0 ;

		         DiscardImage() ;
				 acquired = 0 ;
			     return (0L) ;
			}

			// Work out DIB's width in bytes.

			  // There are at least
			  // 24 * w bits in a DIB line.

			  k = 24 * w ;

			  // A DIB line is always padded up
			  // to the least multiple of 32 bits.
			  // Add bits until k mod 32 == 0.

			  while (k % 32) k++ ;

			  // Divide by eight for bytes.

			  k /= 8 ;

			// Start afresh

			  if (GlobalSize(newbuf)) GlobalFree(newbuf) ;

			// We need an RGB buffer to receive the DIB contents.

			 newbuf = GlobalAlloc(GPTR, 3 * h * w * sizeof(BYTE)) ;
			pnewbuf = (BYTE *) newbuf ;

			// The next function (in ISource21.dll) should convert the DIB to RGB
			// by removing line padding bytes.
			// The input width is the DIB width in BYTES (includes padding)
			// The output width is the RGB buffer width in BYTES (no padding)

			success = _ISCopyBuffer(
				            lpBits, // pointer to source
							k,		// source width, in bytes
							h,		// height of both source and destination
							3 * w,	// destination width, in bytes
							pnewbuf	// pointer to destination
						 ) ;


		   if (success == TRUE) // acquire and RGB buffer creation worked
		   {
			   DiscardImage() ;// don't need the DIB now: free it's memory.
			   HaveImage = 1 ; // so we have an image
			   Previewed = 0 ; // print preview will need to be (re)done
			         GRB = 0 ; // we reset the button

		   // This was a DIB, so adjust the Buffer contents

		   // swap Red & Blue
		   _ISRGBToBGR(pnewbuf, (UINT32)w, (UINT32)h ) ;

		   // flip vertically
		   _ISVertFlipBuf(pnewbuf, (UINT32)(w * 3), (UINT32)h ) ;

		   // Go show it
				ivrc(hWnd, NULL, TRUE) ;

		   }
		   else
		   {
			   HaveImage = 0 ;  // we have the DIB but not the buffer
		       DiscardImage() ;	// so dump DIB
			   GRB = 0 ;		// lift the button
			   ivrc(hWnd, &rctl[Grb], TRUE) ;
		   }
				}
				else  // didn't get the DIB
				{
			GRB = 0 ;
			ivrc(hWnd, &rctl[Grb], TRUE) ;
				}
			break ;

	   case IDM_BRICON:
if (HaveImage)
{
	//toggle the state
	changingbricon ^= 1 ;
	BRC = changingbricon ;
	ivrc(hWnd,&rctl[Brc],FALSE) ;
	
	if (changingbricon)
	{
		// create if it does not exist
		if (GlobalSize(hTempo) == 0)
		{
		 hTempo = GlobalAlloc( GPTR, w * 3 * h * sizeof (BYTE)) ;

		 if (hTempo == NULL)
		MessageBox(NULL,"Allocation has failed","Bricon: Allocate Temp Buffer",MB_OK) ;

		 pTempo = (BYTE *) hTempo ;
		}
		memcpy(pTempo, pnewbuf, w * 3 * h * sizeof(BYTE)) ;
    	changebricon = 1 ;

		ShowWindow(BriConDlg,SW_SHOW) ;
	}
	else goto cancel ;
}
		    break ;

	   case IDM_CANCEL_BCHANGE:
	   case IDM_CANCEL_CCHANGE:
		if (changebricon)
		{
			// just restore original
cancel:		memcpy(pnewbuf, pTempo, w * 3 * h * sizeof(BYTE)) ;
			goto accept ;
		}

		   break ;

	   case IDM_ACCEPT_BCHANGE:
	   case IDM_ACCEPT_CCHANGE:
		   if (changebricon)
		   {
accept:
			// get rid of temporary buffer
			if (GlobalFree(hTempo) == hTempo)
				MessageBox(NULL, "Free Temp buffer has failed.",
				                 "Accept Bricon Change: Free Temp buffer", MB_OK) ;

			// set the bricon parameters to zero state
			nBright = 500 ; fBright = 0.0 ;
			nContrast = 500 ; fContrast = 0.0 ;
			SetDlgItemText(BriConDlg,IDC_ED_BRIGHT,  "0.00") ;
			SetDlgItemText(BriConDlg,IDC_ED_CONTRAST,"0.00") ;
			// hide the dialogue box
			ShowWindow(BriConDlg, SW_HIDE) ;
			// update the image
			BRC = 0 ;
			ivrc(hWnd, NULL, TRUE) ;
			// raise the button
			//ivrc(hWnd,&rctl[Brc],FALSE) ;
			// reset the flags
			changebricon = 0 ;
			changingbricon = 0 ;
		   }
		   break ;

	   case IDM_BRIGHT_UP:
	   case IDM_CONTRAST_UP:

		if (changebricon)
		{
		// recover original
		   memcpy(pnewbuf, pTempo, w * 3 * h * sizeof(BYTE)) ;
		// apply change to it
		   _ISApplyBrightnessContrastToRGB(
			   pnewbuf,
			   w,
			   h,
			   fBright,
			   fContrast
               ) ;
		}

		     oldfBright = fBright ;
		   oldfContrast = fContrast ;

		   ivrc(hWnd,&rcinset,FALSE) ;

		   break ;


	   case IDM_SELECT_RECT:

		 if (HaveImage)
		 {
		   // toggle the current selecting state to its opposite
		   selecting ^= 1 ;
		   // update button state
		   SLR = selecting ;
		   ivrc(hWnd,&rctl[Slr],TRUE) ;

		   // if cancelling, remove any rectangle, prevent cropping
		   if (!SLR && selected) 
		   {
		    ivrc(hWnd,&rcinset,TRUE) ;
		    selected = 0 ;
		   }
		 }

		   break ;

	   case IDM_CROP:

   if (HaveImage) // can't crop if no image loaded
	{
	  // stop any selection in progress
	  if (selecting) selecting = 0 ;
	  // if a selection has been made
	  if (selected)
	  {
		  HGLOBAL   hBuf ;
		     BYTE * pBuf ;
		   UINT32   nw, nh ;

		  // update button state
			CRP = 1 ;
			ivrc(hWnd, &rctl[Crp], FALSE) ;
			UpdateWindow(hWnd) ;

		// 6th Feb 2003
		// There is actually no need to check for an existing buffer if
		// the new, temporary buffer is properly freed after it is used.
		// Code removed.

		 // get the new size
		     nh = rcsel.bottom - rcsel.top + 1 ;
			 nw = rcsel.right - rcsel.left + 1 ;

			hBuf = GlobalAlloc(GPTR, nw * nh * 3 * sizeof(BYTE)) ;
			pBuf = (BYTE *) hBuf ;

			_ISCropImage
				(
				  pnewbuf,
				  w,
				  h,
				  pBuf,
				  rcsel.left,
				  rcsel.top,
				  nw,
				  nh,
				  3
				) ;

		 // New sizes for old

				h = nh ;
				w = nw ;

			if (GlobalSize(newbuf))
			{
				if (GlobalFree( newbuf ) == newbuf)
					MessageBox(NULL, "Free Buffer has failed.", "Crop: Free Buffer", MB_OK) ;
			}

		 // make a new buffer
			 newbuf = GlobalAlloc(GPTR, h * w * 3 * sizeof(BYTE)) ;

			 if (newbuf == NULL)
				 MessageBox(NULL, "Buffer Allocation has failed", "Crop: Buffer allocation", MB_OK) ;

		 // get pointer to it
			 pnewbuf = (BYTE *) newbuf;

		 // copy contents of temporary buffer to new buffer
			 memcpy(pnewbuf, pBuf, h * w * 3 * sizeof(BYTE) ) ;

		 // get rid of temporary buffer
				if (GlobalFree(hBuf) == hBuf)
					MessageBox(NULL, "Free Temp Buffer has failed.", "Crop: Free Temp buffer", MB_OK) ;

			 // cancel selected and selecting
			 // update button states
			 selected = selecting = SLR = 0 ;
			      CRP = 0 ;

			 // assign new size to the globals
				  w_now = w ;
				  h_now = h ;

			 // show the result
			 ivrc(hWnd, NULL, TRUE) ;
	  }
	}
		   break ;

	   case IDM_ROTATE_IMAGE:

  if (HaveImage)
  {
			ROT = 1 ;
			ivrc(hWnd, &rctl[Rot], FALSE) ;
			UpdateWindow(hWnd) ;

	 rot = DialogBox(hInst,
			         MAKEINTRESOURCE(IDD_ROTATE_IMAGE),
					 hWnd,
					 RotateDlgProc
					 ) ;
	 switch( rot )
	 {
	 case IDOK:

		 switch(rot_degrees)
		 {
		 case R90:
			      QR = TRUE ;
			 RotType = R90 ;
			    swap = TRUE ;
			 break ;
		 case R180:
			      QR = TRUE ;
			 RotType = R180 ;
			    swap = FALSE ;
			 break ;
		 case R270:
			      QR = TRUE ;
			 RotType = R270 ;
			    swap = TRUE ;
			 break ;
		 case RFREE:
			      QR = FALSE ;
			 break ;
		 default:
			 break ;
		 }

		 if (QR == TRUE)  // is Quick Rotate operation
		 {
			 // there is no change of memory use

			          _ISQuickRotateImage(
				                           pnewbuf,
				                  (UINT32) w,
				                  (UINT32) h,
				                           RotType,
										   3 ) ;

					  if (swap == TRUE) // 90 or 270 degree spin
					  {
					  temp = w ;
					     w = h ;
					     h = temp ;
					  }
					  w_now = w ;
					  h_now = h ;
					  ROT = 0 ;
			 ivrc(hWnd, NULL, TRUE) ;
		 }
		 else   // is Free Rotate operation.
		 {
			  hTemp = _ISRotateImage(
				                     pnewbuf,
						             w,
							         h,
									 3,
									 NULL,
									 0,
							         FreeRotation,
							         RGB(192, 192, 192), // standard gray spill region
							         //RGB(0, 0, 0),	// black
									 &outw,
									 &outh,
									 FALSE      // Use bi-linear interpolation
			                        ) ;

			 // Get pointer to the temporary buffer
			 pTemp = (BYTE *) hTemp ;

			 // free newbuf
			 if (GlobalSize(newbuf))
			 {
				 if (GlobalFree(newbuf) == newbuf)
					 MessageBox(NULL,"Free Buffer has failed.","Free-Rotate: Free Buffer",MB_OK) ;
			 }

			// get new buffer to match temporary one
			 newbuf = (BYTE *)GlobalAlloc(GPTR, outh * outw * 3 * sizeof(BYTE)) ;

			 // re-assign original pointer to new buffer
			 pnewbuf = newbuf ;

			 // copy contents of temporary buffer to new buffer
			 memcpy(pnewbuf, pTemp, outh * outw * 3 * sizeof(BYTE) ) ;

			 // Free hTemp
					 if (GlobalFree(hTemp) == hTemp)
					MessageBox(NULL, "Free Temp Buffer has failed","Rotate: Free Temp Buffer",MB_OK) ;
//*****
			 // Crop this rotated image to the original size.
			 // By default, the rotation was about a point
			 // in the centre of the original image.
			 // The cropped image has the same centre.

			pBuf = (BYTE *)GlobalAlloc(GPTR, w * h * 3 * sizeof(BYTE)) ;

			_ISCropImage
				(
				  pnewbuf,		// source
				  outw,
				  outh,
				  pBuf,			// destination
				  (outw - w)/2,
				  (outh - h)/2,
				  w,
				  h,
				  3
				) ;


			if (GlobalSize(newbuf))
			{
				if (GlobalFree( newbuf ) == newbuf)
					MessageBox(NULL, "Free Buffer has failed.", "Crop: Free Buffer", MB_OK) ;
			}

		 // make a new buffer
			 newbuf = (BYTE *)GlobalAlloc(GPTR, h * w * 3 * sizeof(BYTE)) ;

			 if (newbuf == NULL)
				 MessageBox(NULL, "Buffer Allocation has failed", "Crop: Buffer allocation", MB_OK) ;

			 pnewbuf = newbuf ;

		 // copy contents of temporary buffer to new buffer
			 memcpy(pnewbuf, pBuf, h * w * 3 * sizeof(BYTE) ) ;


				if (GlobalFree( pBuf ) == pBuf)
					MessageBox(NULL, "Free pBuf has failed.", "Crop: Free Buffer", MB_OK) ;

//*******
			 
			 // assign new dimensions
			 //h = h_now = outh ; w = w_now = outw ;
				h_now = h ; w_now = w ;

					 
			           ROT = 0 ; // lift button

			 // Go show rotated pic
			 ivrc(hWnd, NULL, TRUE) ;
		 }

		 break ; // IDOK

	 case IDCANCEL:
	 default:
		 ROT = 0 ;
		 ivrc(hWnd,&rctl[Rot],FALSE) ;
		 break ; // IDCANCEL

	 } // switch(rot)
  }
		   break ;

	 case IDM_RESIZE_IMAGE:

	if (HaveImage)
	{
	 RSZ = 1 ;
	 ivrc(hWnd,&rctl[Rsz],FALSE) ;
	 UpdateWindow(hWnd) ;

	 rez = DialogBox(hInst,
			         MAKEINTRESOURCE(IDD_RESIZE_IMAGE),
					 hWnd,
					 ResizeDlgProc
					 ) ;

	 switch (rez)
	{
		 HGLOBAL   hBuf ;
		    BYTE * pBuf ;

	 case IDOK:
		 switch (rsz_size)
		 {
		 case S1024:
			 wnew = 1024 ;
			 hnew =  768 ;
			 break ;
		 case S320:
			 wnew =  320 ;
			 hnew =  240 ;
			 break ;
		 case S160:
			 wnew =  160 ;
			 hnew =  120 ;
			 break ;
		 case SCUST:
			 wnew = rsz_x ;
			 hnew = rsz_y ;
			 break ;
		 case S640:
		 default:
			 wnew = 640 ;
			 hnew = 480 ;
			 break ;
		 }  // end switch (rsz_size)

		 StartWait() ;

		hBuf = GlobalAlloc(GPTR, wnew * hnew * 3 * sizeof(BYTE)) ;

		if (hBuf == NULL)
			MessageBox(NULL,"Allocation failed", "Resize: Temp. Buffer Allocation", MB_OK) ;

		pBuf = (BYTE *) hBuf ;

			   _ISResizeImage
				   (
				    pnewbuf, // source
					w,		 // old size
					h,
					pBuf,	 // destination
					wnew,	 // new size
					hnew,
					3		 // 3 bytes/pix (24 bit)		     
				   ) ;

		// need a new buffer: free the old one.
		if (GlobalSize(newbuf))
		{
			if (GlobalFree(newbuf) == newbuf) // free has failed
			MessageBox(NULL,"Free memory has failed","Resize: Free Allocation",MB_OK) ;
		}

		// make the new one
		   newbuf = GlobalAlloc(GPTR, hnew * wnew * 3 * sizeof(BYTE)) ;

		   if (newbuf == NULL)
		   MessageBox(NULL,"Allocation has failed","Resize: Buffer Allocation",MB_OK) ;

		// get a pointer to it
		  pnewbuf = (BYTE *)newbuf ;

		// copy data from hBuf
		  memcpy(pnewbuf,  // destination
			        pBuf,  // source
					hnew * wnew * 3 * sizeof(BYTE)) ;

		// don't need hBuf now, free it
		  if (GlobalFree(hBuf) == hBuf)
		MessageBox(NULL,"Free Temp Buffer has failed","Resize: Free Temp Buffer",MB_OK) ;

		  h = h_now = hnew ; w = w_now = wnew ;

		  ivrc(hWnd, NULL, TRUE) ;
		  EndWait() ;

		 break ; // end case IDOK


	 case IDCANCEL:
		 break ; // end case IDCANCEL

	 default:
		 break ;
	 } // end switch (rez)


	 RSZ = 0 ;
	 ivrc(hWnd,&rctl[Rsz],FALSE) ;
	 UpdateWindow(hWnd) ;

	} // end if (HaveImage)

		   break ; // end case IDM_RESIZE_IMAGE

	   case IDM_USE_IMAGE: // Put loaded/acquired/modified image into work
	   if (HaveImage)
	   {
		   USE = SavefromImagery = 1 ;
		   ivrc(hWnd, &rctl[Use], FALSE) ;

		   // first save it from Imagery to a file
		   SendMessage(hWnd,WM_COMMAND,IDM_SAVE_IMAGE,0L) ;

		   if (!saved) {
			             USE = 0 ;
		                 ivrc(hWnd, &rctl[Use], FALSE) ;
		                 break ;
		               }          

		   // to get it into the archive
		   // first copy the Imagery file string to the BW file string
		   strcpy(szFile, szImageryFile) ;
		   
		   // then open that file in the BW while updating records
		   skipgetfile = 1 ;
		   SendMessage(hWndCtrl,WM_COMMAND,IDM_OPEN_FILE,0L) ;

		   // now restore to normal operation. File is now in work.
		   skipgetfile = 0 ;

		   // hide Acquire window
		   ShowWindow(hWnd,SW_HIDE) ;
		   
		   // raise the 'pass to BW' button
		   // cancel the "saved" flag ready for next use of it.
		   USE = saved = 0 ;
		   
		   // reset the acquire button in control window
		   SendMessage(hWndCtrl, WM_COMMAND, IDM_TWAIN_ACQUIRE, 0L) ;
		   break ;
	   }

	   case IDM_SAVE_IMAGE:
	   if (HaveImage)
	   {
				HISDEST hDest ;

		   SAC = SavefromImagery = 1 ;
		   ivrc(hWnd, &rctl[Sac], FALSE) ;
		   UpdateWindow(hWnd) ;

		  // get the file name
		   if (SaveBudFile( hWnd ) == TRUE)
		   {

		  // pick out the extension
		  strcpy( Extension, GetExt(DropPath(szImageryFile)) ) ;

		  if (!_stricmp(".BMP",Extension))	// save as a BMP
		  {

				hDest = _ISOpenFileDest(szImageryFile) ;

				_ISWriteBMP
				(
				  hDest,
				  pnewbuf,
				  w,
		  (_int32)h,
				  24,
				  0,
				  NULL,
				  FALSE
				) ;

				_ISCloseDest(hDest) ;

			  saved = 1 ;
			    SAC = SavefromImagery = 0 ;
			  ivrc(hWnd, &rctl[Sac], FALSE) ;
		  }


		  if (!_stricmp(".JPG",Extension))  // save as JPEG
		  {

				hDest = _ISOpenFileDest(szImageryFile) ;

				_ISAddJPGOutputText(szImageryFile) ; // write image file-name to the image file as embedded text

			_ISWriteJPG
				(
				  hDest,
				  pnewbuf,
				  w,
				  h,
				  JPGQuality,
				  0,
				  24,
				  NULL
				) ;

				_ISCloseDest(hDest) ;

				_ISClearJPGOutputText() ;

		     saved = 1 ;
			   SAC = SavefromImagery = 0 ;
			 ivrc(hWnd, &rctl[Sac], FALSE) ; 
		  }
		 captured = 0 ;
	    }
		   else	{ 
			      saved = 0 ;
		            SAC = SavefromImagery = 0 ;
				  ivrc(hWnd, &rctl[Sac], FALSE) ;
				  goto dropit ;
		        }
	   }
dropit:	   break ;

	   case IDM_MAKE_TEST_BUD: // not yet fully implemented

		   TST ^= 1 ;
		 ivrc(hWnd, &rctl[Tst], FALSE) ;
		 if (TST)
		 {
		 tstbud = DialogBox(hInst,
			                MAKEINTRESOURCE(IDD_CREATE_IMAGE),
					        hWnd,
					        TestBudDlgProc
			               ) ;

		 switch( tstbud )
		 {
		 case IDOK:
			 TST = 0 ;
		 ivrc(hWnd, &rctl[Tst], FALSE) ;
			 break ;

		 case IDCANCEL:
			 TST = 0 ;
		 ivrc(hWnd, &rctl[Tst], FALSE) ;
			 break ;

		 default:
			 break ;
		 }
		 }
		   break ;

	   case IDM_PRINT_NOW:
	if (HaveImage)
	{
		 PRN = 1 ;
		 ivrc(hWnd, &rctl[Prn], FALSE) ;
		 UpdateWindow(hWnd) ;

/* Display the PRINT dialog box. */ 

		if ( PrintDlg(&pd) == TRUE )
		{
		 hPrnDC = pd.hDC ;  // get the printer's DC, and other things

         if (!(GetDeviceCaps(hPrnDC, RASTERCAPS) & RC_BITBLT))
            { 
              DeleteDC(hPrnDC);
			  msgbox = 1 ;
              MessageBox(hWnd, 
                         "Printer cannot display bitmaps.", 
                         "Device Error", 
                          MB_OK);
			  msgbox = 0 ;
	                      break ;
            }
	SetMapMode(hPrnDC,MM_TEXT) ;

       EnableWindow(hWnd, FALSE);

                 di.cbSize = sizeof(DOCINFO); 
                 di.lpszDocName = "" ; 
                 di.lpszOutput = (LPTSTR) NULL; 
                 di.lpszDatatype = (LPTSTR)NULL ; 
                 di.fwType = 0;

				 // Prepare the printer to print document
				 
                 if (StartDoc(hPrnDC, &di) <= 0)
					 MessageBox(NULL,"No StartDoc","StartDoc()",MB_OK) ;

				 // Prepare the printer to print this page

                 if (StartPage(hPrnDC) <= 0)
					 MessageBox(NULL,"No StartPage","StartPage()", MB_OK);

				 // Set up the page....

			if (!Previewed)
			{

				 // Get pixels per printer-dimension.

                 WPels = GetDeviceCaps(hPrnDC, LOGPIXELSX); // for printer, these are 
                 HPels = GetDeviceCaps(hPrnDC, LOGPIXELSY); // dots per REAL inch (dpi)

				 // dots are equivalent to pixels on the printer

			 physwidth = (double)GetDeviceCaps(hPrnDC, PHYSICALWIDTH)   ; // in Device Units
			physheight = (double)GetDeviceCaps(hPrnDC, PHYSICALHEIGHT)  ; // in Device Units

			 // Device units are (inches * current printer dpi)
			 // which implies that dpi = physwidth/realpaperwid

			// which says that the image width in pixels needs to be stretched to
			// the required printed width in inches times the dpi.



		   physoffsetx = (double)GetDeviceCaps(hPrnDC, PHYSICALOFFSETX) ; // dots 
		   physoffsety = (double)GetDeviceCaps(hPrnDC, PHYSICALOFFSETY) ; // dots

	// Use the defaults.
	xLeft = (int)((double)WPels * xoinch - physoffsetx) ; // printer pixels (dots)
	 yTop = (int)((double)HPels * yoinch - physoffsety) ; // printer pixels (dots)

	 pwid = (int)((double)WPels *  winch) ;
	 phyt = (int)((double)HPels *  hinch) ;

			}
		
		// set up a memory DC

                 htemp  = CreateCompatibleDC(hdc);
		
		// select the bitmap into it
 				 
                 opBm = SelectObject(htemp, hPrn) ;
				 
		// stretch the bitmap to the printer DC

                 if (StretchBlt
					    (hPrnDC,
					     xLeft,
						 yTop,
						 pwid,
						 phyt,
                         htemp, 0, 0, 
                         w, h, 
                         SRCCOPY) == FALSE
					)
						 MessageBox(NULL,
						 "No StretchBlt",
						 "StretchBlt()",
						 MB_OK);
 		// clean up

				 SelectObject(htemp, opBm) ;
				 DeleteDC(htemp) ;

		// Spool (Print) the page

                 EndPage(hPrnDC);

		// Stop the printing
				 
                 EndDoc(hPrnDC);
				 
				 EnableWindow(hWnd,TRUE) ;

	   // final clean up.

			DeleteDC(hPrnDC) ;
		}
			PRN = 0 ;
			ivrc(hWnd, &rctl[Prn], FALSE) ;
			UpdateWindow(hWnd) ;
	}
		   break ;

	   case IDM_PRINT_PREVIEW:
    if (HaveImage)
	{
		layout ^= 1 ;
		LAY = layout ;
		ivrc(hWnd,&rctl[Lay],FALSE) ;
		UpdateWindow(hWnd) ;

		if (layout)
		{
		ShowWindow(hWndLayout, SW_SHOW) ;
		UpdateWindow(hWndLayout) ;
		}
		else
		{
		ShowWindow(hWndLayout, SW_HIDE) ;
		}
	}
		   break ;

	   default: break ;
	   } // end switch()

	   break ; //end WM_COMMAND


	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);

		hmemDCc = CreateCompatibleDC(hdc) ;

         GetObject(bmOEX, sizeof(BITMAP), &bm ) ;
         oBmc = SelectObject(hmemDCc, bmOEX) ;

	   if( !PMX )							   // open existing button
               SelectObject(hmemDCc, bmPMX) ;  // show unselected
            else
               SelectObject(hmemDCc, bmPMXO) ; // show selected

               BitBlt(hdc, rctl[Pmx].left,	  // show button
                           rctl[Pmx].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !OEX )							   // open existing button
               SelectObject(hmemDCc, bmOEX) ;  // show unselected
            else
               SelectObject(hmemDCc, bmOEXO) ; // show selected

               BitBlt(hdc, rctl[Oex].left,	  // show button
                           rctl[Oex].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !BRC )							   // Brightness/Contrast btn
               SelectObject(hmemDCc, bmBRC) ;  // show unselected
            else
               SelectObject(hmemDCc, bmBRCO) ; // show selected

               BitBlt(hdc, rctl[Brc].left,	   // show button
                           rctl[Brc].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !GRB )							   // Acquire button
               SelectObject(hmemDCc, bmGRB) ;  // show unselected
            else
               SelectObject(hmemDCc, bmGRBO) ; // show selected

               BitBlt(hdc, rctl[Grb].left,	  // show button
                           rctl[Grb].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !SAC )							   // Acquire button
               SelectObject(hmemDCc, bmSAC) ;  // show unselected
            else
               SelectObject(hmemDCc, bmSACO) ; // show selected

               BitBlt(hdc, rctl[Sac].left,	  // show button
                           rctl[Sac].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !USE )							   // use in BW button
               SelectObject(hmemDCc, bmUSE) ;  // show unselected
            else
               SelectObject(hmemDCc, bmUSEO) ; // show selected

               BitBlt(hdc, rctl[Use].left,	  // show button
                           rctl[Use].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !ROT )							   // Rotate image button
               SelectObject(hmemDCc, bmROT) ;  // show unselected
            else
               SelectObject(hmemDCc, bmROTO) ; // show selected

               BitBlt(hdc, rctl[Rot].left,	  // show button
                           rctl[Rot].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !SLR )							   // select rectangle button
               SelectObject(hmemDCc, bmSLR) ;  // show unselected
            else
               SelectObject(hmemDCc, bmSLRO) ; // show selected

               BitBlt(hdc, rctl[Slr].left,	  // show button
                           rctl[Slr].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !CRP )							   // crop to rect. button
               SelectObject(hmemDCc, bmCRP) ;  // show unselected
            else
               SelectObject(hmemDCc, bmCRPO) ; // show selected

               BitBlt(hdc, rctl[Crp].left,	  // show button
                           rctl[Crp].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !RSZ )							   // resize button
               SelectObject(hmemDCc, bmRSZ) ;  // show unselected
            else
               SelectObject(hmemDCc, bmRSZO) ; // show selected

               BitBlt(hdc, rctl[Rsz].left,	  // show button
                           rctl[Rsz].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !TST )							   // Make test image button
               SelectObject(hmemDCc, bmTST) ;  // show unselected
            else
               SelectObject(hmemDCc, bmTSTO) ; // show selected

               BitBlt(hdc, rctl[Tst].left,	  // show button
                           rctl[Tst].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !PRN )							   // print now button
               SelectObject(hmemDCc, bmPRN) ;  // show unselected
            else
               SelectObject(hmemDCc, bmPRNO) ; // show selected

               BitBlt(hdc, rctl[Prn].left,	   // show button
                           rctl[Prn].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !LAY )							   // print preview button
               SelectObject(hmemDCc, bmLAY) ;  // show unselected
            else
               SelectObject(hmemDCc, bmLAYO) ; // show selected

               BitBlt(hdc, rctl[Lay].left,	   // show button
                           rctl[Lay].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

		SelectObject(hmemDCc, oBmc) ;
		ReleaseDC(hWnd, hmemDCc) ;

		if (HaveImage)
		{
		   // Fit image in window
			if (ShowGrabs)
			{
				w = wd = grabwid ;
				h = ht = grabhyt ;
			}
			else
			{
				    wd = w = w_now ; // start with exact match
				    ht = h = h_now ;
			}
				aspect = (double)h / (double)w ;

				// Leave a "passe partout" for buttons etc

				GetClientRect(hWnd,&rc) ;
				winset = rc.right - rc.left - 64 ;
				hinset = rc.bottom - rc.top - 64 ;

				// Go fit
				while ( wd > winset || ht > hinset )
				{
					wd-- ;
					ht = MulDiv(wd, h, w) ;
				}

				while ( wd < winset && ht < hinset )
				{
					wd++ ;
					ht = MulDiv(wd, h, w) ;
				}

				SetRect(&rcinset,32,32,wd + 32,ht + 32) ;

		// Need a memory DC   
		hmemDC = CreateCompatibleDC(hdc) ;

		if (ShowGrabs)	hBm = hGrab ;
		else
		{
		// Convert RGB buffer to ordinary DDB
		hBm = _ISRGBToHBITMAP
				(
				pnewbuf,
		(UINT32)w,
		(UINT32)h,
				NULL,
				hdc
				) ;

		pCpybuf = pnewbuf ;
		}

		// Get the DDB into the memory DC
		oBm = SelectObject(hmemDC, hBm) ;

		// Best quality option
		SetStretchBltMode(hdc, COLORONCOLOR) ;
	   
		// Show the image

		if (ShowGrabs)
		StretchBlt( hdc,			// Destination DC
					32,				// x Top Left Corner destination
					32,		        // y TLC destination
					wd, ht,			// pixel width & height in destination
					hmemDC,			// Source DC
					0, 0,			// x,y TLC source
					grabwid, grabhyt,	// width & height in source
					SRCCOPY );		// raster operation (copy)
		else
		StretchBlt( hdc,			// Destination DC
					32,				// x Top Left Corner destination
					32,		        // y TLC destination
					wd, ht,			// pixel width & height in destination
					hmemDC,			// Source DC
					0, 0,			// x,y TLC source
					w, h,			// width & height in source
					SRCCOPY );		// raster operation (copy)

		// Legend
		captured = 0 ;              // allow new capture

		// Clean up
		SelectObject(hmemDC, oBm) ;
		DeleteDC(hmemDC) ;
	 // 07/02/2003 BUGFIX. !!! next line was missing,
     // and was vital to proper memory clearance.
	    DeleteObject(hBm) ;
		}
        EndPaint(hWnd, &ps);
        break;

        case WM_TIMER:

		switch(wParam)
		{
			case IDT_TIPDWELL:
			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 // This time-out timer kicked in when the tip was shown.
			 // if the cursor is still in the control,
			 // this timer message kills the tip.
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 DestroyWindow(hWndInfo[UseCtl]) ;
				 CurrentTip = (HWND)NULL ;
				 hWndOfCurrentTip = (HWND)NULL ;
			 }
			 // the timer is killed in any event
			 KillTimer(hWnd, IDT_TIPDWELL) ;
			 Dwelling[UseCtl] = 0 ;
				return 0L ;

			case IDT_TIPDEFER:

			// the delay-show timer is killed in any event
			 KillTimer(hWnd,IDT_TIPDEFER) ;
			 Deferred[UseCtl] = 0 ;

			 GetCursorPos(&cupt) ;		    // is ind'p't of WndProc
			 ScreenToClient(hWnd,&cupt) ;	// and mouse capture
			 //Delay-show timer WaitTim kicks in when cursor enters control:
			 //If cursor still there on this message, show tip.

			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 PutTip(hWnd, -20, 3) ;

			// start up the time-out timer which turns off the tip
			//  onTim = SetTimer(hWnd,IDT_TIPDWELL,tDwell,NULL) ;
			 }
			    break ;

		  case IDT_VOCTIMER:

			GetCursorPos(&cupt) ;
			ScreenToClient(hWnd,&cupt) ;
			if (PtInRect(&rctl[UseBtn],cupt))
			{
				PlaySound(szVocTipWav[UseBtn], NULL, SND_ASYNC) ;
			}
			KillTimer(hWnd,VTim) ;

			   break ;

		}
		return 0L ;
		break ;

	case WM_CREATE:

		BriConDlg = CreateDialog(
			hInst,
			MAKEINTRESOURCE(IDD_BRICON),
			hWnd,
			BriConDlgProc
			) ;

pd.lStructSize = sizeof(PRINTDLG); 
pd.hDevMode = (HANDLE) NULL; 
pd.hDevNames = (HANDLE) NULL; 
pd.Flags = PD_RETURNDC; 
pd.hwndOwner = hWnd; 
pd.hDC = (HDC) NULL; 
pd.nFromPage = 1; 
pd.nToPage = 1; 
pd.nMinPage = 1; 
pd.nMaxPage = 1; 
pd.nCopies = 1; 
pd.hInstance = (HANDLE) NULL; 
pd.lCustData = 0L; 
pd.lpfnPrintHook = (LPPRINTHOOKPROC) NULL; 
pd.lpfnSetupHook = (LPSETUPHOOKPROC) NULL; 
pd.lpPrintTemplateName = (LPSTR) NULL; 
pd.lpSetupTemplateName = (LPSTR)  NULL; 
pd.hPrintTemplate = (HANDLE) NULL; 
pd.hSetupTemplate = (HANDLE) NULL; 

         bmSLR = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_RECT)) ;
        bmSLRO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_RECT_ON)) ;
         bmROT = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ROTATE_IMAGE)) ;
        bmROTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ROTATE_IMAGE_ON)) ;
         bmGRB = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GRAB_IMAGE)) ;
        bmGRBO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GRAB_IMAGE_ON)) ;
         bmSAC = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SAV_IMAGE)) ;
        bmSACO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SAV_IMAGE_ON)) ;
         bmUSE = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_USE_IMAGE)) ;
        bmUSEO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_USE_IMAGE_ON)) ;
         bmCRP = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CROP_IMAGE)) ;
        bmCRPO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CROP_IMAGE_ON)) ;
         bmPRN = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PRINT_NOW)) ;
        bmPRNO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PRINT_NOW_ON)) ;
         bmLAY = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PRINT_PREVIEW)) ;
        bmLAYO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PRINT_PREVIEW_ON)) ;
         bmOEX = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_OPEN_EXIST)) ;
        bmOEXO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_OPEN_EXIST_ON)) ;
         bmRSZ = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_RESIZE_IMAGE)) ;
        bmRSZO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_RESIZE_IMAGE_ON)) ;
         bmBRC = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BRICON)) ;
        bmBRCO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BRICON_ON)) ;
         bmTST = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_MAKE_TEST_BUD)) ;
        bmTSTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_MAKE_TEST_BUD_ON)) ;
        bmPMX  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PICK_N_MIX)) ;
        bmPMXO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PICK_N_MIX_ON)) ;
		return 0L ;
		break ;

	case WM_DESTROY:
		DestroyWindow(BriConDlg) ;
		DestroyWindow(hWndLayout) ;
		DeleteObject(bmSLR) ;
		DeleteObject(bmSLRO) ;
		DeleteObject(bmROT) ;
		DeleteObject(bmROTO) ;
		DeleteObject(bmGRB) ;
		DeleteObject(bmGRBO) ;
		DeleteObject(bmSAC) ;
		DeleteObject(bmSACO) ;
		DeleteObject(bmCRP) ;
		DeleteObject(bmCRPO) ;
		DeleteObject(bmUSE) ;
		DeleteObject(bmUSEO) ;
		DeleteObject(bmPRN) ;
		DeleteObject(bmPRNO) ;
		DeleteObject(bmLAY) ;
		DeleteObject(bmLAYO) ;
		DeleteObject(bmOEX) ;
		DeleteObject(bmOEXO) ;
		DeleteObject(bmRSZ) ;
		DeleteObject(bmRSZO) ;
		DeleteObject(bmBRC) ;
		DeleteObject(bmBRCO) ;
		DeleteObject(bmTST) ;
		DeleteObject(bmTSTO) ;
		DeleteObject(bmPMX) ;
		DeleteObject(bmPMXO) ;
		if (hCapt)
		DeleteObject(hCapt) ;
		if (hBm)
		DeleteObject(hBm) ;
		if (hDib)
		DiscardImage() ;
		if (hPrnDC)
		DeleteDC(hPrnDC) ;
		if (hPrn)
		DeleteObject(hPrn) ;
		if (GlobalSize(newbuf))
		{
			       if (GlobalFree( newbuf ) == newbuf)
					   MessageBox(NULL, 
					   "GlobalFree() failure during Imagery Clean Up", 
					   "GlobalFree() Problem",
					   MB_OK);
		}
		return 0L ;
		break ;

case WM_NCHITTEST: // works for any mouse event in this window

	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

case WM_MOUSEMOVE:

		pt.x = LOWORD(lParam) ;
		pt.y = HIWORD(lParam) ;

		if (showtips || sounds)
		{
			GetCursorPos(&cpt) ;
			ScreenToClient(hWnd, &cpt) ;
 		    GetTip( hWnd, Oex, Tst, cpt ) ;
			if (sounds)
 		    GetVoc( hWnd, Oex, Brc, cpt ) ;
		}

		  if (HaveImage)
		  {
			  curinimage = (PtInRect(&rcinset,pt) == TRUE) ? 1 : 0 ;

		   if (selecting && curinimage)
		   {
			if (wParam & MK_LBUTTON)   // Left Button down
			{
			 hdc = GetDC(hWnd) ;
			 oPen = SelectObject(hdc, whitePen) ;
			 SetROP2(hdc,R2_XORPEN) ;
			 if (prev == TRUE)  // wipe old rectangle by redrawing it
			 {
				 MoveToEx(hdc, ptstart.x,   ptstart.y,(LPPOINT)NULL) ;
				   LineTo(hdc, ptprevend.x, ptstart.y) ;
				   LineTo(hdc, ptprevend.x, ptprevend.y) ;
				   LineTo(hdc, ptstart.x,   ptprevend.y) ;
				   LineTo(hdc, ptstart.x,   ptstart.y) ;
			 }

			 // get new vertex
			 ptnow.x = pt.x ;
			 ptnow.y = pt.y ;

			 // draw new rectangle
			 MoveToEx(hdc, ptstart.x, ptstart.y,(LPPOINT)NULL) ;
			 LineTo(hdc, ptnow.x,   ptstart.y) ;
			 LineTo(hdc, ptnow.x,   ptnow.y) ;
			 LineTo(hdc, ptstart.x, ptnow.y) ;
			 LineTo(hdc, ptstart.x, ptstart.y) ;

			 // say we're selecting
			 prev = TRUE ;

			 // new vertex becomes old vertex for next  
			 ptprevend = ptnow ;

			 SelectObject(hdc, oPen) ;
			 ReleaseDC(hWnd,hdc) ;
			}
		  }
		  }
		break ;

	case WM_LBUTTONDOWN:

		pt.x = LOWORD(lParam) ;
		pt.y = HIWORD(lParam) ;

		if (PtInRect(&rctl[Pmx],pt))
		{
			picknmix ^= 1;
			PMX = !picknmix ;
			ivrc(hWnd, &rctl[Pmx], TRUE) ;
			if (picknmix)
			{
            Clicked[Pmx] = 1 ;
			KillTip(hWnd,Pmx) ;
			SendMessage(hWnd,WM_COMMAND,IDM_PICK_N_MIX,0L) ;
			}
		}     

		if (PtInRect(&rctl[Oex],pt))
		{
            Clicked[Oex] = 1 ;
			KillTip(hWnd,Oex) ;
			SendMessage(hWnd,WM_COMMAND,IDM_OPEN_EXISTING,0L) ;
		}
		
		if (PtInRect(&rctl[Grb],pt))
		{
            Clicked[Grb] = 1 ;
			KillTip(hWnd,Grb) ;
			SendMessage(hWnd,WM_COMMAND,IDM_ACQUIRE_IMAGE,0L) ;
		}

		if (PtInRect(&rctl[Tst],pt))
		{
            Clicked[Tst] = 1 ;
			KillTip(hWnd,Tst) ;
			SendMessage(hWnd,WM_COMMAND,IDM_MAKE_TEST_BUD,0L) ;
		}

		if (HaveImage)
		{

		if (PtInRect(&rctl[Sac],pt))
		{
            Clicked[Sac] = 1 ;
			KillTip(hWnd,Sac) ;
			SendMessage(hWnd,WM_COMMAND,IDM_SAVE_IMAGE,0L) ;
		}

		if (PtInRect(&rctl[Use],pt))
		{
            Clicked[Use] = 1 ;
			KillTip(hWnd,Use) ;
			SendMessage(hWnd,WM_COMMAND,IDM_USE_IMAGE,0L) ;
		}

		if (PtInRect(&rctl[Slr],pt))
		{
            Clicked[Slr] = 1 ;
			KillTip(hWnd,Slr) ;
			SendMessage(hWnd,WM_COMMAND,IDM_SELECT_RECT,0L) ;
		}

		if (PtInRect(&rctl[Crp],pt))
		{
            Clicked[Crp] = 1 ;
			KillTip(hWnd,Crp) ;
			SendMessage(hWnd,WM_COMMAND,IDM_CROP,0L) ;
		}

		if (PtInRect(&rctl[Rot],pt))
		{
            Clicked[Rot] = 1 ;
			KillTip(hWnd,Rot) ;
			SendMessage(hWnd,WM_COMMAND,IDM_ROTATE_IMAGE,0L) ;
		}

		if (PtInRect(&rctl[Rsz],pt))
		{
            Clicked[Rsz] = 1 ;
			KillTip(hWnd,Rsz) ;
			SendMessage(hWnd,WM_COMMAND,IDM_RESIZE_IMAGE,0L) ;
		}

		if (PtInRect(&rctl[Brc],pt))
		{
            Clicked[Brc] = 1 ;
			KillTip(hWnd,Brc) ;
			SendMessage(hWnd,WM_COMMAND,IDM_BRICON,0L) ;
		}

		if (PtInRect(&rctl[Prn],pt))
		{
            Clicked[Prn] = 1 ;
			KillTip(hWnd,Prn) ;
			SendMessage(hWnd,WM_COMMAND,IDM_PRINT_NOW,0L) ;
		}

		if (PtInRect(&rctl[Lay],pt))
		{
            Clicked[Lay] = 1 ;
			KillTip(hWnd,Lay) ;
			SendMessage(hWnd,WM_COMMAND,IDM_PRINT_PREVIEW,0L) ;
		}

		if (selecting && curinimage)
		{
		  if (selected)
		  {
		   // just refresh inset to get rid of old rectangle
			ivrc(hWnd,&rcinset,FALSE) ;
			UpdateWindow(hWnd) ;
			selected = 0 ;
		  }

		   // get the starting mouse position
			            ptstart.x = pt.x ;
		                ptstart.y = pt.y ;
		   
		   // confine cursor to image inset
					     ptclip.x = rcinset.left ;
					     ptclip.y = rcinset.top ;
					ClientToScreen(hWnd,&ptclip) ;
					  rcclip.left = ptclip.x ;
					  rcclip.top  = ptclip.y ;

					     ptclip.x = rcinset.right ;
					     ptclip.y = rcinset.bottom ;
					ClientToScreen(hWnd,&ptclip) ;
					rcclip.right  = ptclip.x ;
					rcclip.bottom = ptclip.y ;

					ClipCursor(&rcclip) ;
		}
		}
		break ;

    case WM_LBUTTONUP:

		pt.x = LOWORD(lParam) ;
		pt.y = HIWORD(lParam) ;

		if (selecting && curinimage)
		{
				prev = FALSE ;
				ClipCursor(NULL) ;

			// sort out order of vertices.
			// dimensions are client-relative, i.e. (0,0) is at top left.

				if (ptstart.x > ptnow.x) // cursor is to left of start
				{
					xa = ptnow.x ;
				    xb = ptstart.x ;
				}
				else                     // cursor is to right of start
				{
					xa = ptstart.x ;
					xb = ptnow.x ;
				}

				if (ptstart.y > ptnow.y) // cursor is above start
				{
					ya = ptnow.y ;
				    yb = ptstart.y ;
				}
				else					 // cursor is below start
				{
					ya = ptstart.y ;
					yb = ptnow.y ;
				}

		// Now we want these vertices image-relative

		// 07 May 2001:
		// Change to integer operation using MulDiv().
		// Multiplies first, then divides, to reduce rounding errors.
		// Should be faster.
		/*****************************************************
				xad = (UINT32)floor((double)w * (double)(xa - rcinset.left) / (double)wd) ;
				yad = (UINT32)floor((double)h * (double)(ya - rcinset.top ) / (double)ht) ;
				xbd = (UINT32)floor((double)w * (double)(xb - rcinset.left) / (double)wd) ;
				ybd = (UINT32)floor((double)h * (double)(yb - rcinset.top ) / (double)ht) ;
		 *****************************************************/

				xad = (UINT32)MulDiv(w, xa - rcinset.left, wd) ;
				yad = (UINT32)MulDiv(h, ya - rcinset.top,  ht) ;
				xbd = (UINT32)MulDiv(w, xb - rcinset.left, wd) ;
				ybd = (UINT32)MulDiv(h, yb - rcinset.top,  ht) ;

				SetRect(
					&rcsel,
					xad,
					yad,
					xbd,
					ybd
					) ;
				selected = 1 ;
		}
	    break ;

	case WM_SIZE:
	case WM_MOVE:

		ivrc(hWnd, NULL, TRUE) ;
		UpdateWindow(hWnd) ;

		break ;

        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
    }

    return ((long)NULL);
}

/*******************************************************************
	               Print Layout Procedure
 *******************************************************************/
long CALLBACK  PrintLayoutProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
	  PAINTSTRUCT  ps ;
	          HDC  hdc, hmemDC ;
			 SIZE  sz ;
	static   HPEN  hshPen, oPen ;
	static HBRUSH  hshadow, oBsh ;
	static HBITMAP oPrn ;
	static   wc, hc ;	 //  pixel dimensions of client area 
	static   wp, hp ;	 // "paper" pixel dimensions in client 
	static   lpof, rpof ;//	"paper" horz. pixel margins in client
	static   tpof, bpof ;// "paper" vert. pixel margins in client
	static   xo, yo ;    //  pixel offsets to TLC of image in "paper"
	static   xoc, yoc ;	 //  pixel offsets to TLC of image in client
    static   wi, hi ;    //  pixel image dimensions in "paper"
	double   Ri ;        //  ratio of height to width of image
	double   Rp ;        //  ratio of height to width of paper

    static    RECT rcim ;	 //  to contain the preview image
	static    RECT rcdrag ;  //  the bottom right corner drag box
	static    RECT rcur ;	 //  matches drag box for cursor trapping
	static HCURSOR OldCursor ;
	static   POINT mouse, pt ;
	static         dx, dy, dragging ;
	static    char buffer1[80] ;
	static    char buffer2[80] ;
	  char	       szDevString[120] ;
	  char        *szDriver, *szPrinter, *szPort ;

	switch(message)
	{
	case WM_COMMAND:
		
			switch (LOWORD(wParam))
			{

	case WM_MOUSEGONE:
		   if (CurrentTip != (HWND)NULL)
		   RemoveTip() ;
		   return 0L ;

	default: break ;
			}

			break ;
 
	case WM_NCHITTEST: // works for any mouse event in this window

	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

	case WM_MOUSEMOVE:

		mouse.x = LOWORD(lParam) ;
		mouse.y = HIWORD(lParam) ;

	   OldCursor = PtInRect(&rcim,mouse)   ?
		          (PtInRect(&rcdrag,mouse) ?
				         SetCursor(LoadCursor(NULL,IDC_SIZENWSE)) :
	                     SetCursor(LoadCursor(NULL,IDC_SIZEALL))) :
	                     SetCursor(LoadCursor(NULL,IDC_ARROW)) ;
		   
	   if (PtInRect(&rcim, mouse))  // we're somewhere in the image
	   {
		   if (wParam & MK_LBUTTON) // we're dragging something
		   {
		    if (!PtInRect(&rcdrag, mouse)) // it's the whole thing
		    {
				// new top and left margins wrt paper
		         xo = mouse.x - dx ;                           // pixels
		     xoinch = (double)xo * realpaperwid / (double)wp ; // inches  
		         yo = mouse.y - dy ;						   // pixels
		     yoinch = (double)yo * realpaperhyt / (double)hp ; // inches
			}
			else                           // it's the bottom right corner.
			{
				// new image size wrt paper
		         wi = (dx + mouse.x) - xo ;					   // pixels
		      winch = (double)wi * realpaperwid / (double)wp ; // inches 
		         hi = (dy + mouse.y) - yo ;					   // pixels
		      hinch = (double)hi * realpaperhyt / (double)hp ; // inches
			}

	// New right and bottom inch margins.
	xrinch = realpaperwid - (winch + xoinch) ;
	ybinch = realpaperhyt - (hinch + yoinch) ;
		   
 		   ivrc(hWnd,&rcim,TRUE) ; // clear previous image

		  // get the preview window's DC
		   hdc = GetDC(hWnd) ;

		  // Use text extents to clear old text areas.
		   GetTextExtentPoint32(hdc, buffer1, strlen(buffer1), &sz) ;
		   SetRect(&rctxtwipe, 5, 2, 5 + sz.cx, 2 + sz.cy) ;
		   ivrc(hWnd, &rctxtwipe, TRUE) ;

		   GetTextExtentPoint32(hdc, buffer2, strlen(buffer2), &sz) ;
		   SetRect(&rctxtwipe, 5, 2 + sz.cy, 5 + sz.cx, 2 + 2*sz.cy) ;
		   ivrc(hWnd, &rctxtwipe, TRUE) ;

		   // Clean up.
		   ReleaseDC(hWnd, hdc) ;

		   }
	   }

		break ;

	case WM_LBUTTONDOWN:

		mouse.x = LOWORD(lParam) ;
		mouse.y = HIWORD(lParam) ;
		
		if (PtInRect(&rcim, mouse))
		{
		if (!PtInRect(&rcdrag, mouse))
		  {
			dx = mouse.x - xo ;		   //we're to drag the whole image
			dy = mouse.y - yo ;		   // locking TLC to mouse
		  }
		else
		  {
			dragging = 1 ;			   // we're to drag the corner
			dx = (xo + wi) - mouse.x ; // locking BRC to mouse
			dy = (yo + hi) - mouse.y ;
		  }
		}
 		return 0 ;
		break ;

	case WM_LBUTTONUP:

		dragging = 0 ;	   //   not dragging corner now, so
		ClipCursor(NULL) ; //   free cursor from drag handle

		return 0 ;
		break ;

	case WM_MOVE:
	case WM_SIZE:
	case WM_WINDOWPOSCHANGED:
		ivrc(hWnd, NULL, TRUE) ;
		UpdateWindow(hWnd) ;
		return 0 ;
		break ;

	case WM_PAINT:
		 hdc = BeginPaint(hWnd, &ps) ;
		GetClientRect(hWnd, &rclay) ;
	     SelectObject(hdc, hfnt) ;
	     SetTextColor(hdc, RGB(255,  0,  0)) ;
	        SetBkMode(hdc, TRANSPARENT) ;

		if (!Previewed)	 // if this is the first preview...
		{
		 // Get the DC of the default printer

			GetProfileString(
				"windows",
				"device",
				",,,",
				szDevString,
				120 ) ;

			if (strcmp(szDevString,",,,") == 0)
			{
				MessageBox(NULL,
				"Default Printer",
				"No Printer found",
				MB_OK) ;
				break ;
			}

    if ((szPrinter = strtok(szDevString, 
               (const char *) ",")) 
            && (szDriver = strtok ((char *) NULL, 
               (const char *) ", ")) 
            && (szPort = strtok ((char *) NULL, 
               (const char *) ", "))) 
        hPrnDC = CreateDC(
		                  NULL,
						  szPrinter,
						  NULL,
						  NULL
						  ) ;

	     WPels = GetDeviceCaps(hPrnDC, LOGPIXELSX) ; // true dpi of printer
		 HPels = GetDeviceCaps(hPrnDC, LOGPIXELSY) ;
		 physoffsetx = GetDeviceCaps(hPrnDC, PHYSICALOFFSETX) ;
		 physoffsety = GetDeviceCaps(hPrnDC, PHYSICALOFFSETY) ;

		 Previewed = 1 ;
		}

		// client area pixel width and height
		  wc = rclay.right  - rclay.left ;
		  hc = rclay.bottom - rclay.top ;

		// aspect ratio of real paper. (A4 only for now)
		  Rp = realpaperhyt / realpaperwid ;

		// pixel offsets to image of paper.
		rpof = 10 ;	// right			     
		bpof = 10 ;	// bottom
		lpof = 32 ;	// left, with room for text and/or buttons
		tpof = 32 ;	// top, ditto

		// Make sure the "paper" fits in
		// whatever window is available,
		// while leaving a passe-partout.

		// as long as neither dimension is too large...
		while (
			    (wp < wc - (rpof + lpof))
				         &&
				(hp < hc - (bpof + tpof))
			  )
		{
			wp++ ;
			hp = (int)(Rp * (double)wp) ;
		}

		// as long as one or both of the dimensions is too large...
		while (
			    (wp > wc - (rpof + lpof))
				         ||
				(hp > hc - (bpof + tpof))
			  )
		{
			wp-- ;
			hp = (int)(Rp * (double)wp) ;
		}

		hshadow = CreateSolidBrush(RGB(145, 145, 145)) ;
		   oBsh = SelectObject(hdc, hshadow) ;

		 hshPen = CreatePen(PS_SOLID, 1, RGB(145, 145, 145)) ;
		   oPen = SelectObject(hdc, hshPen) ;

	// first show the "shadow"...	
		Rectangle(hdc, lpof + 5, tpof + 5, wp + lpof + 5, hp + tpof + 5) ;

		SelectObject(hdc, oPen) ;
		SelectObject(hdc, oBsh) ;
		       
		oBsh = SelectObject(hdc, GetStockObject(WHITE_BRUSH)) ;
		oPen = SelectObject(hdc, blackPen) ;

	// ...then overlay with the image of the paper.
		Rectangle(hdc, lpof, tpof, wp + lpof, hp + tpof) ;

		SelectObject(hdc, oPen) ;
		SelectObject(hdc, oBsh) ;
		DeleteObject(hshadow) ;
		DeleteObject(hshPen) ;

   // Image aspect ratio from original Bitmap pixel sizes
	Ri = (double)h_now / (double)w_now ;

	// Printed inch dimensions of image
	hinch = Ri * winch ;

	// Right and bottom inch margins.
	xrinch = realpaperwid - (winch + xoinch) ;
	ybinch = realpaperhyt - (hinch + yoinch) ;

	sprintf(buffer1,
		"Left Mrg. %3.2f Right Mrg. %3.2f. [%3.2f in. X %3.2f in.]",
		    xoinch,xrinch,winch, hinch ) ;

	GetTextExtentPoint32(hdc, buffer1, strlen(buffer1), &sz) ;

	TextOut(hdc, 5, 2, buffer1, strlen(buffer1)) ;

	sprintf(buffer2,
		"Top Mrg. %3.2f Bottom Mrg. %3.2f",
		 yoinch, ybinch ) ;

	GetTextExtentPoint32(hdc, buffer2, strlen(buffer2), &sz) ;

	TextOut(hdc, 5, 2 + sz.cy, buffer2, strlen(buffer2)) ;

	// Offsets to TLC of preview image from TLC of "paper"
    xo = (int)((double)wp * xoinch / realpaperwid) ;
	yo = (int)((double)hp * yoinch / realpaperhyt) ;

	// Offsets to TLC of preview image from TLC of client area
	rcim.left     = xoc = xo + lpof ;
	rcim.top      = yoc = yo + tpof ;

	// Pixel dimensions of displayed preview image
	wi = (int)(wp * winch / realpaperwid) ;
	hi = (int)(hp * hinch / realpaperhyt) ;

	// Offsets to Bottom Right of displayed preview image.
	rcim.right    = rcim.left + wi ;
	rcim.bottom   = rcim.top  + hi ;

	// Drag box at Bottom Right corner
	rcdrag.left   =	rcim.right  - 10 ;
	rcdrag.top    =	rcim.bottom - 10 ;
	rcdrag.right  =	rcim.right ;
	rcdrag.bottom =	rcim.bottom ;

	// The dimensions per the Printer DC
	xLeft = (int)((double)WPels * xoinch - physoffsetx) ;
	 yTop = (int)((double)HPels * yoinch - physoffsety) ;
	 pwid = (int)((double)WPels *  winch) ;
	 phyt = (int)((double)HPels *  hinch) ;

		hPrn = _ISRGBToHBITMAP
				(
				pCpybuf,
		(UINT32)w_now,
		(UINT32)h_now,
				NULL,
				hdc
				) ;


	hmemDC = CreateCompatibleDC(hdc) ;
	  oPrn = SelectObject(hmemDC, hPrn) ;

	SetStretchBltMode(hdc, COLORONCOLOR) ;

	StretchBlt(hdc,
		       xoc,
			   yoc,
			   wi,
			   hi,
			   hmemDC,
			   0, 0,
			   w_now, h_now,
			   SRCCOPY
			   ) ;

	if (dragging) // keep cursor inside new drag handle
	    {
			pt.x = rcdrag.left;
			pt.y = rcdrag.bottom ;
			ClientToScreen(hWnd, &pt) ;
			rcur.left   = pt.x ;
			rcur.bottom = pt.y ;

			pt.x = rcdrag.right ;
			pt.y = rcdrag.top ;
			ClientToScreen(hWnd,&pt) ;
			rcur.right = pt.x ;
			rcur.top   = pt.y ;

			ClipCursor(&rcur) ;
	    }

		SelectObject(hmemDC, oPrn) ;
		DeleteDC(hmemDC) ;
		//DeleteObject(hPrn) ;
		EndPaint(hWnd, &ps) ;
		break ;
 
        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
	}
 return ((long)NULL) ;
}

void SubText1(HWND hWnd,
			  UINT32 w,
			  UINT32 h,
			  UINT32 ht,
			  int show_mem_use,
			  UINT32 before,
			  UINT32 after)
{
	  HDC hdc ;
	HFONT ofnt ;
	 SIZE sz ;
	 char buff1[180] ;
	 char buff2[180] ;
	  int len ;
//	 char * szFileName ;

		hdc = GetDC(hWnd) ;
	   ofnt = SelectObject(hdc, hfnt) ;
		SetBkMode( hdc, TRANSPARENT ) ;

  if (captured)
	    sprintf(buff1,"%ld x %ld -- Capture.", w, h) ;
		else
		sprintf(buff1,"%ld x %ld   %s", w, h, DropPath(szImageryFile)) ;

        GetTextExtentPoint32(hdc, buff1, len = strlen(buff1), &sz) ;
		TextOut(hdc, 32, ht + 34, buff1, len) ;

  if (show_mem_use)
		{
	    sprintf(buff2,"Mem. pool before %ld, after %ld, diff. %ld",
			    before, after, after - before) ;
        GetTextExtentPoint32(hdc, buff2, len = strlen(buff2), &sz) ;
		TextOut(hdc, 32, ht + 34 + sz.cy, buff2, len) ;
		}


		SelectObject(hdc,ofnt) ;
		ReleaseDC(hWnd,hdc) ;
}

BOOL CALLBACK TestBudDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static HWND hW ;
	static HWND UDTLam, UDTWid, UDTLen ;
	static HWND EDTLam, EDTWid, EDTLen ;
	static HWND UDINse, UDIGrn, UDPNse, UDPGrn ;
	static HWND EDINse, EDIGrn, EDPNse, EDPGrn ;
	static HWND hFill,  hOutl,  hFCol,  hOCol, hBCol ;

	static     BOOL T = TRUE ;
	static     BOOL F = FALSE ;
	static CHOOSECOLOR chcol ;
	static COLORREF custcols[16] ;
	static     char buff[80] ;
	static    short TLm, TW, TLn ;
	static	  short In,  PN, IG, PG ; 

	switch( msg )
	{
	case WM_INITDIALOG:

		UDTLam = GetDlgItem(hDlg, IDC_U_TEST_LAMBDA) ;
		UDTWid = GetDlgItem(hDlg, IDC_U_TEST_WIDTH ) ;
		UDTLen = GetDlgItem(hDlg, IDC_U_TEST_LENGTH) ;

		UDINse = GetDlgItem(hDlg, IDC_U_IMG_NOISE  ) ;
		UDIGrn = GetDlgItem(hDlg, IDC_U_IMG_GRANUL ) ;
	    UDPNse = GetDlgItem(hDlg, IDC_U_PROF_NOISE ) ;
		UDPGrn = GetDlgItem(hDlg, IDC_U_PROF_GRANUL) ;

	sprintf(buff,"%4.2f",TLambda) ;
	SetDlgItemText(hDlg,IDC_E_TEST_LAMBDA,buff) ;
	sprintf(buff,"%4.2f",TWidth) ;
	SetDlgItemText(hDlg,IDC_E_TEST_WIDTH,buff) ;
	sprintf(buff,"%4.2f",TLength) ;
	SetDlgItemText(hDlg,IDC_E_TEST_LENGTH,buff) ;
	
	sprintf(buff,"%4.2f",TImgNoise) ;
	SetDlgItemText(hDlg,IDC_E_IMG_NOISE,buff) ;
	sprintf(buff,"%4.2f",TImgGrain) ;
	SetDlgItemText(hDlg,IDC_E_IMG_GRANUL,buff) ;
	sprintf(buff,"%4.2f",TPrfNoise) ;
	SetDlgItemText(hDlg,IDC_E_PROF_NOISE,buff) ;
	sprintf(buff,"%4.2f",TPrfGrain) ;
	SetDlgItemText(hDlg,IDC_E_PROF_GRANUL,buff) ;

				SetUDRng(UDTLam, 2000, -2000) ;

				TLm = (short)(100.0 * (TLambda + 20.0) - 2000.0) ;

	            SetUDPos(UDTLam, TLm) ;

				SetUDRng(UDTWid, 200, 0) ;

				TW = (short)(TWidth * 100.0) ;

			    SetUDPos(UDTWid, TW) ;

				SetUDRng(UDTLen, 400, 0) ;

				TLn = (short)(TLength * 100.0) ;

	            SetUDPos(UDTLen, TLn) ;

				SetUDRng(UDINse, 200, 0) ;

				In = (short)(TImgNoise * 2.0) ;

	            SetUDPos(UDINse, In) ;

				SetUDRng(UDIGrn, 200, 0) ;

				IG = (int)(TImgGrain * 2.0) ;

	            SetUDPos(UDIGrn, IG) ;

				SetUDRng(UDPNse, 200, 0) ;

				PN =(short)(TPrfNoise * 2.0) ;

	            SetUDPos(UDPNse, PN) ;

				SetUDRng(UDPGrn, 200, 0) ;

				PG = (short)(TPrfGrain * 2.0) ;

	            SetUDPos(UDPGrn, PG) ;

		EDTLam = GetDlgItem(hDlg, IDC_E_TEST_LAMBDA) ;
		EDTWid = GetDlgItem(hDlg, IDC_E_TEST_WIDTH ) ;
		EDTLen = GetDlgItem(hDlg, IDC_E_TEST_LENGTH) ;

		EDINse = GetDlgItem(hDlg, IDC_E_IMG_NOISE  ) ;
		EDIGrn = GetDlgItem(hDlg, IDC_E_IMG_GRANUL ) ;

		EDPNse = GetDlgItem(hDlg, IDC_E_PROF_NOISE ) ;
		EDPGrn = GetDlgItem(hDlg, IDC_E_PROF_GRANUL) ;

		 hFill = GetDlgItem(hDlg, IDC_C_FILLED     ) ;
		 hOutl = GetDlgItem(hDlg, IDC_C_OUTLINED   ) ;

		 hFCol = GetDlgItem(hDlg, IDC_B_FILL_COL   ) ;
		 hOCol = GetDlgItem(hDlg, IDC_B_OUTLINE_COL) ;
		 hBCol = GetDlgItem(hDlg, IDC_B_BK_COL     ) ;

		 CheckDlgButton(hDlg, IDC_C_FILLED,   filltestbud) ;
		 CheckDlgButton(hDlg, IDC_C_OUTLINED, outltestbud) ;

		   memset(&chcol,'\0', sizeof(CHOOSECOLOR)) ;

           chcol.lStructSize  = sizeof(CHOOSECOLOR) ; 
           chcol.hwndOwner    = hDlg ; 
		   chcol.lpCustColors = custcols ;
		   chcol.rgbResult    = RGB( 192, 192, 192 ) ;
           chcol.Flags        = CC_FULLOPEN|CC_RGBINIT ; 

		return TRUE ;
		break ;

    case WM_VSCROLL:  // one of the U/D controls has been changed

			      hW = (HWND)lParam ;

		if (hW == UDTLam) 
		{

				TLm = GetUDPos(UDTLam) ; 
					
			TLambda = ((double)TLm + 2000.0)/100.0 - 20.0 ; 

		    sprintf(buff,"%4.2f", TLambda) ;
			SetDlgItemText(hDlg,IDC_E_TEST_LAMBDA,buff) ;
		}

		if (hW == UDTWid)
		{
			TWidth = 0.01 * (double)GetUDPos(UDTWid) ;

		    sprintf(buff,"%4.2f", TWidth) ;
			SetDlgItemText(hDlg,IDC_E_TEST_WIDTH,buff) ;
		}

		if (hW == UDTLen)
		{
		     TLength = 0.01 * (double)GetUDPos(UDTLen) ;

		    sprintf(buff,"%4.2f", TLength) ;
			SetDlgItemText(hDlg,IDC_E_TEST_LENGTH,buff) ;
		}

		if (hW == UDINse)
		{
			TImgNoise = 0.5 * (double)GetUDPos(UDINse) ;

		    sprintf(buff,"%4.2f", TImgNoise) ;
			SetDlgItemText(hDlg,IDC_E_IMG_NOISE,buff) ;
		}

		if (hW == UDIGrn)
		{
			TImgGrain = 0.5 * (double)GetUDPos(UDIGrn) ;

		    sprintf(buff,"%4.2f", TImgGrain) ;
			SetDlgItemText(hDlg,IDC_E_IMG_GRANUL,buff) ;
		}

		if (hW == UDPNse)
		{
			TPrfNoise = 0.5 * (double)GetUDPos(UDPNse) ;

		    sprintf(buff,"%4.2f", TPrfNoise) ;
			SetDlgItemText(hDlg,IDC_E_PROF_NOISE,buff) ;
		}

		if (hW == UDPGrn)
		{
			TPrfGrain = 0.5 * (double)GetUDPos(UDPGrn) ;

		    sprintf(buff,"%4.2f", TPrfGrain) ;
			SetDlgItemText(hDlg,IDC_E_PROF_GRANUL,buff) ;
		}

		break ;

	case WM_COMMAND:

		switch (HIWORD(wParam)) // pick up edit-box notifications
		{
		case EN_UPDATE:  // an edit box was changed.

			switch(LOWORD(wParam)) // which edit box was altered?
			{

		case IDC_E_TEST_LAMBDA: // was Lambda

			// fetch the new text
			GetDlgItemText(hDlg,IDC_E_TEST_LAMBDA,buff,80) ;

			// convert to double
			TLambda = atof(buff) ;

			// set the U/D ctl position to match
	        SetUDPos(UDTLam, (int)(100.0 * (TLambda + 20.0) - 2000.0)) ;

			break ;

		case IDC_E_TEST_WIDTH:
			GetDlgItemText(hDlg,IDC_E_TEST_WIDTH,buff,80) ;
			TWidth = atof(buff) ;
			SetUDPos(UDTWid, (int)(100.0 * TWidth)) ;
			break ;

		case IDC_E_TEST_LENGTH:
			GetDlgItemText(hDlg,IDC_E_TEST_LENGTH,buff,80) ;
			TLength = atof(buff) ;
			SetUDPos(UDTLen, (int)(100.0 * TLength)) ;
			break ;

		case IDC_E_IMG_NOISE:
			GetDlgItemText(hDlg,IDC_E_IMG_NOISE,buff,80) ;
			TImgNoise = atof(buff) ;
			SetUDPos(UDINse, (int)(2.0 * TImgNoise)) ;
			break ;

		case IDC_E_IMG_GRANUL:
			GetDlgItemText(hDlg,IDC_E_IMG_GRANUL,buff,80) ;
			TImgGrain = atof(buff) ;
			SetUDPos(UDIGrn, (int)(2.0 * TImgGrain)) ;
			break ;

		case IDC_E_PROF_NOISE:
			GetDlgItemText(hDlg,IDC_E_PROF_NOISE,buff,80) ;
			TPrfNoise = atof(buff) ;
			SetUDPos(UDPNse, (int)(2.0 * TPrfNoise)) ;
			break ;

		case IDC_E_PROF_GRANUL:
			GetDlgItemText(hDlg,IDC_E_PROF_GRANUL,buff,80) ;
			TPrfGrain = atof(buff) ;
			SetUDPos(UDPGrn, (int)(2.0 * TPrfGrain)) ;
			break ;

			default:
				break ;
			} //end switch on LOWORD(wParam) after notification

			break ;

		default:
			break ;
		} //end switch on HIWORD(wParam) giving notification

		switch (LOWORD(wParam))
		{
		case IDC_B_FILL_COL:

			chcol.rgbResult = FillColour ;
			ChooseColor(&chcol) ;
			FillColour = chcol.rgbResult ;
			break ;

		case IDC_B_OUTLINE_COL:

			chcol.rgbResult = OutlineColour ;
			ChooseColor(&chcol) ;
			OutlineColour = chcol.rgbResult	;
			break ;

		case IDC_B_BK_COL:

			chcol.rgbResult = BackColour ;
			ChooseColor(&chcol) ;
			BackColour = chcol.rgbResult ;
			break ;

		case IDC_C_FILLED:
		 filltestbud = IsDlgButtonChecked(hDlg, IDC_C_FILLED) ;
			break ;

		case IDC_C_OUTLINED:
		 outltestbud = IsDlgButtonChecked(hDlg, IDC_C_OUTLINED) ;
			break ;

	case IDOK:
		EndDialog(hDlg, IDOK) ;
		break ;

	case IDCANCEL:
		EndDialog(hDlg, IDCANCEL) ;
		break ;

	default:
		break ;
		} // switch (LOWORD(wParam))

	      break ; //WM_COMMAND

		default:
			break ;
	} // switch (msg)

 return FALSE ;
}


BOOL CALLBACK BriConDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
static	  HWND ScrBright, ScrContrast, hW ;
static	  HWND EdBright,  EdContrast ;
static     int bigstep   = 100 ;
static     int smallstep =  10 ;
static     int nPos ;

	char buff[20] ;

	switch(msg)
	{

case WM_INITDIALOG:
	ScrBright   = GetDlgItem(hDlg, IDC_BRIGHT) ;
	SetScrollRange(ScrBright, SB_CTL, 0, 1000, TRUE) ;
	  SetScrollPos(ScrBright, SB_CTL, 1000 - nBright, TRUE) ;

	ScrContrast = GetDlgItem(hDlg, IDC_CONTRAST) ;
	SetScrollRange(ScrContrast,SB_CTL, 0, 1000, TRUE) ;
	  SetScrollPos(ScrContrast, SB_CTL, 1000 - nContrast, TRUE) ;

	EdBright = GetDlgItem(hDlg, IDC_ED_BRIGHT) ;
	fBright = 1.0 - 2.0 * (1000.0 - (double)nBright)/1000.0 ;
	sprintf(buff,"%1.2f",fBright) ;

			 SendMessage(EdBright,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

	EdContrast = GetDlgItem(hDlg, IDC_ED_CONTRAST) ;
	fContrast = 1.0 - 2.0 * (1000.0 - (double)nContrast)/1000.0 ;
	sprintf(buff,"%1.2f",fContrast) ;

			 SendMessage(EdContrast,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

	return (TRUE) ;
	break ;	// end WM_INITDIALOG

case WM_VSCROLL:
			      hW = (HWND)lParam ;
			 	nPos =  (int)HIWORD(wParam) ;

		switch (LOWORD(wParam))
		{
		 case SB_THUMBTRACK:
			 if (hW == ScrBright)
			 {
				 SetFocus(ScrBright) ;
			 nBright = 1000 - nPos ;
			 SetScrollPos(ScrBright, SB_CTL, nPos, TRUE) ;
			 fBright = 1.0 - 2.0 * (1000.0 - (double)nBright)/1000.0 ;
			 sprintf(buff,"%1.2f",fBright) ;

			 SendMessage(EdBright,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq,WM_COMMAND, IDM_BRIGHT_UP, 0L) ;
			 }

			 if (hW == ScrContrast)
			 {
				 SetFocus(ScrContrast) ;
			 nContrast = 1000 - nPos ;
			 SetScrollPos(ScrContrast, SB_CTL, nPos, TRUE) ;
			 fContrast = 1.0 - 2.0 * (1000.0 - (double)nContrast)/1000.0 ;
			 sprintf(buff,"%1.2f",fContrast) ;

			 SendMessage(EdContrast,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq, WM_COMMAND, IDM_CONTRAST_UP, 0L) ;
			 }
			 break ;

		 case SB_LINEUP:
			 if (hW == ScrBright)
			 {
				 SetFocus(ScrBright) ;
			 nBright += smallstep ;
			 if (nBright > 1000) nBright = 1000 ;
			 SetScrollPos(ScrBright, SB_CTL, 1000 - nBright, TRUE) ;
			 fBright = 1.0 - 2.0 * (1000.0 - (double)nBright)/1000.0 ;
			 sprintf(buff,"%1.2f",fBright) ;

			 SendMessage(EdBright,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq,WM_COMMAND, IDM_BRIGHT_UP, 0L) ;
			 }

			 if (hW == ScrContrast)
			 {
				 SetFocus(ScrContrast) ;
			 nContrast += smallstep ;
			 if (nContrast > 1000) nContrast = 1000 ;
			 SetScrollPos(ScrContrast, SB_CTL, 1000 - nContrast, TRUE) ;
			 fContrast = 1.0 - 2.0 * (1000.0 - (double)nContrast)/1000.0 ;
			 sprintf(buff,"%1.2f",fContrast) ;

			 SendMessage(EdContrast,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq, WM_COMMAND, IDM_CONTRAST_UP, 0L) ;
			 }
			 break ;

		 case SB_LINEDOWN:
			 if (hW == ScrBright)
			 {
				 SetFocus(ScrBright) ;
			 nBright -= smallstep ;
			 if (nBright < 0) nBright = 0 ;
			 SetScrollPos(ScrBright, SB_CTL, 1000 - nBright, TRUE) ;
			 fBright = 1.0 - 2.0 * (1000.0 - (double)nBright)/1000.0 ;
			 sprintf(buff,"%1.2f",fBright) ;

			 SendMessage(EdBright,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq,WM_COMMAND, IDM_BRIGHT_UP, 0L) ;
			 }

			 if (hW == ScrContrast)
			 {
				 SetFocus(ScrContrast) ;
			 nContrast -= smallstep ;
			 if (nContrast < 0) nContrast = 0 ;
			 SetScrollPos(ScrContrast, SB_CTL, 1000 - nContrast, TRUE) ;
			 fContrast = 1.0 - 2.0 * (1000.0 - (double)nContrast)/1000.0 ;
			 sprintf(buff,"%1.2f",fContrast) ;

			 SendMessage(EdContrast,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq, WM_COMMAND, IDM_CONTRAST_UP, 0L) ;
			 }
			 break ;

		 case SB_PAGEUP:
				 SetFocus(ScrBright) ;
			 if (hW == ScrBright)
			 {
			 nBright += bigstep ;
			 if (nBright > 1000) nBright = 1000 ;
			 SetScrollPos(ScrBright, SB_CTL, 1000 - nBright, TRUE) ;
			 fBright = 1.0 - 2.0 * (1000.0 - (double)nBright)/1000.0 ;
			 sprintf(buff,"%1.2f",fBright) ;

			 SendMessage(EdBright,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq,WM_COMMAND, IDM_BRIGHT_UP, 0L) ;
			 }

			 if (hW == ScrContrast)
			 {
				 SetFocus(ScrContrast) ;
			 nContrast += bigstep ;
			 if (nContrast > 1000) nContrast = 1000 ;
			 SetScrollPos(ScrContrast, SB_CTL, 1000 - nContrast, TRUE) ;
			 fContrast = 1.0 - 2.0 * (1000.0 - (double)nContrast)/1000.0 ;
			 sprintf(buff,"%1.2f",fContrast) ;

			 SendMessage(EdContrast,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq, WM_COMMAND, IDM_CONTRAST_UP, 0L) ;
			 }
		 break ;

		 case SB_PAGEDOWN:
			 if (hW == ScrBright)
			 {
				 SetFocus(ScrBright) ;
			 nBright -= bigstep ;
			 if (nBright < 0) nBright = 0 ;
			 SetScrollPos(ScrBright, SB_CTL, 1000 - nBright, TRUE) ;
			 fBright = 1.0 - 2.0 * (1000.0 - (double)nBright)/1000.0 ;
			 sprintf(buff,"%1.2f",fBright) ;

			 SendMessage(EdBright,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq, WM_COMMAND, IDM_BRIGHT_UP, 0L) ;
			 }

			 if (hW == ScrContrast)
			 {
				 SetFocus(ScrContrast) ;
			 nContrast -= bigstep ;
			 if (nContrast < 0) nContrast = 0 ;
			 SetScrollPos(ScrContrast, SB_CTL, 1000 - nContrast, TRUE) ;
			 fContrast = 1.0 - 2.0 * (1000.0 - (double)nContrast)/1000.0 ;
			 sprintf(buff,"%1.2f",fContrast) ;

			 SendMessage(EdContrast,
				         WM_SETTEXT,
						 (WPARAM)0,
				         (LPARAM)(LPCTSTR)buff) ;

			 SendMessage(hWndAcq, WM_COMMAND, IDM_CONTRAST_UP, 0L) ;
			 }
			 break ;

		 default: break ;
		}

	break ;

case WM_COMMAND:

	   switch(LOWORD(wParam))
	   {
	   case IDC_BRIGHT:
		   break ;

	   case IDC_CONTRAST:
		   break ;
	   
	   case IDC_ED_BRIGHT:
		   switch(HIWORD(wParam))
		   {
		   case EN_UPDATE:
			   SendMessage(EdBright,
				           WM_GETTEXT,
				           (WPARAM)20,
			      (LPARAM)(LPCTSTR)buff
				) ;

			   fBright = atof(buff) ;
			   nBright = (int)(1000.0 * (1.0 - (1.0 - fBright)/2.0)) ;
			   SetScrollPos(ScrBright, SB_CTL, 1000 - nBright, TRUE) ;

			   break ;
		   default:break ;
		   }
		   break ;

	   case IDC_ED_CONTRAST:
		   switch(HIWORD(wParam))
		   {
		   case EN_UPDATE:
			   SendMessage(EdContrast,
				           WM_GETTEXT,
				           (WPARAM)20,
			      (LPARAM)(LPCTSTR)buff
				) ;

			   fContrast = atof(buff) ;
			   nContrast = (int)(1000.0 * (1.0 - (1.0 - fContrast)/2.0)) ;
			   SetScrollPos(ScrContrast, SB_CTL, 1000 - nContrast, TRUE) ;

			   break ;
		   default:break ;
		   }
		   break ;

	   case IDOK:
	   SendMessage(hWndAcq,WM_COMMAND,IDM_ACCEPT_BCHANGE,0L) ;
	   ShowWindow(BriConDlg, SW_HIDE) ;

		   break ; // end IDOK
				    
	   case IDCANCEL:
	   SendMessage(hWndAcq,WM_COMMAND,IDM_CANCEL_BCHANGE,0L) ;
	   ShowWindow(BriConDlg, SW_HIDE) ;

		   break ; // end IDCANCEL

	   default: break ;
	   } // end switch (wParam)

	   break ; // end WM_COMMAND

	default: break ; 
	}// end switch (msg)

return (FALSE) ;

} // end BriConDlgProc() ;


BOOL CALLBACK RotateDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
  static char cbuf[20] = "0.0" ;

	switch(msg)
	{

case WM_INITDIALOG:

	SetDlgItemText(hDlg, IDC_ED_ROTATE, cbuf) ;

	switch (rot_degrees)
	{
	case R180:
	CheckRadioButton(hDlg,
		             IDC_90,
					 IDC_FREE_ROTATE,
					 IDC_180
					 ) ;
		break ;

	case R270:
	CheckRadioButton(hDlg,
		             IDC_90,
					 IDC_FREE_ROTATE,
					 IDC_270
					 ) ;
		break ;

	case RFREE:
	CheckRadioButton(hDlg,
		             IDC_90,
					 IDC_FREE_ROTATE,
					 IDC_FREE_ROTATE
					 ) ;
		break ;

	case R90:
	default:
	CheckRadioButton(hDlg,
		             IDC_90,
					 IDC_FREE_ROTATE,
					 IDC_90
					 ) ;
	    break ;
	  }

	return TRUE ;
	break ;

case WM_COMMAND:
	switch(LOWORD(wParam))
	{
	case IDOK:
		if (IsDlgButtonChecked(hDlg, IDC_90))
			rot_degrees = R90 ;
		if (IsDlgButtonChecked(hDlg, IDC_180))
			rot_degrees = R180 ;
		if (IsDlgButtonChecked(hDlg, IDC_270))
			rot_degrees = R270 ;
		if (IsDlgButtonChecked(hDlg, IDC_FREE_ROTATE))
		{
			rot_degrees = RFREE ;
			GetDlgItemText(hDlg, IDC_ED_ROTATE, cbuf, 20) ;
			// rotation sense to agree with convention: anticlock positive
			FreeRotation = -atof(cbuf) / r2d ; 
		}
		EndDialog(hDlg,IDOK) ;
		break ;

	case IDCANCEL:
		EndDialog(hDlg,IDCANCEL) ;
		break ;

	default:
		break ;
	} // switch (wParam)


	break ;
  }	// switch (msg)

		return FALSE ;
}

BOOL CALLBACK ResizeDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
  static char xbuf[20] = "100" ;
  static char ybuf[20] = "100" ;
  static HWND xhandle, yhandle ;
  static UINT32 orsz_x, orsz_y ;
  static BOOL snafu ;

	switch(msg)
	{

case WM_INITDIALOG:

	SetDlgItemText( hDlg, IDC_X_DIMENSION, xbuf ) ;
	SetDlgItemText( hDlg, IDC_Y_DIMENSION, ybuf ) ;

	if (keep_aspect)
		CheckDlgButton(hDlg, IDC_KEEP_ASPECT, 1) ;
	else
		CheckDlgButton(hDlg, IDC_KEEP_ASPECT, 0) ;

	orsz_x = rsz_x ;
	orsz_y = rsz_y ;

	switch (rsz_size)
	{
	case S1024:
		CheckRadioButton(
			hDlg,
			IDC_1024x768,
			IDC_CUSTOM,
			IDC_1024x768
			) ;
		break ;

	case S320:
		CheckRadioButton(
			hDlg,
			IDC_1024x768,
			IDC_CUSTOM,
			IDC_320x240
			) ;
		break ;

	case SCUST:
		CheckRadioButton(
			hDlg,
			IDC_1024x768,
			IDC_CUSTOM,
			IDC_CUSTOM
			) ;
		break ;
		
	case S640:
	default:
		CheckRadioButton(
			hDlg,
			IDC_1024x768,
			IDC_CUSTOM,
			IDC_640x480
			) ;
		break ;
	}

	return TRUE ;
	break ;


case WM_COMMAND:

	switch(HIWORD(wParam)) // pick up notifications
	{
	case EN_UPDATE:
		switch(LOWORD(wParam))
		{
		case IDC_X_DIMENSION: // the text is about to change to---
		rsz_x = GetDlgItemInt(hDlg,IDC_X_DIMENSION,&snafu,FALSE) ;
			break ;
		case IDC_Y_DIMENSION: // the text is about to change to---
		rsz_y = GetDlgItemInt(hDlg,IDC_Y_DIMENSION,&snafu,FALSE) ;
			break ;
		default:
			break ;
		}
		break ;

	default:
		break ;
	}

	switch(LOWORD(wParam))
	{
/*
	case IDC_X_DIMENSION:
	rsz_x = GetDlgItemInt(hDlg,IDC_X_DIMENSION,&snafu,FALSE) ;


	if (keep_aspect) // produces a stack fault--thru' reentrance, obviously
	{
	rsz_y = (UINT32)ceil((double)rsz_x * (double)h_now / (double)w_now) ;
	sprintf(ybuf,"%ld",rsz_y) ;
	SetDlgItemText(hDlg, IDC_Y_DIMENSION, ybuf) ;
	}
		break ;
*/
/*
	case IDC_Y_DIMENSION:
	rsz_y = GetDlgItemInt(hDlg,IDC_Y_DIMENSION,&snafu,FALSE) ;

	
	if (keep_aspect)
	{
	rsz_x = (UINT32)ceil((double)rsz_y * (double)w_now / (double)h_now) ;
	sprintf(xbuf,"%ld",rsz_x) ;
	SetDlgItemText(hDlg, IDC_X_DIMENSION, xbuf) ;
	}
		break ;
*/
	case IDOK:
		if (IsDlgButtonChecked(hDlg, IDC_1024x768))
			rsz_size = S1024 ;
		if (IsDlgButtonChecked(hDlg, IDC_640x480))
			rsz_size = S640 ;
		if (IsDlgButtonChecked(hDlg, IDC_320x240))
			rsz_size = S320 ;
		if (IsDlgButtonChecked(hDlg, IDC_160x120))
			rsz_size = S160 ;
		if (IsDlgButtonChecked(hDlg, IDC_KEEP_ASPECT))
			keep_aspect = 1 ;
		else
			keep_aspect = 0 ;

		if (IsDlgButtonChecked(hDlg, IDC_CUSTOM))
		{
			rsz_size = SCUST ;

			GetDlgItemText(hDlg, IDC_X_DIMENSION, xbuf, 20) ;
			rsz_x = atoi(xbuf) ;

	if (keep_aspect)
	{
	rsz_y = (UINT32)MulDiv(rsz_x, h_now, w_now) ;
	sprintf(ybuf,"%ld",rsz_y) ;
	SetDlgItemText(hDlg, IDC_Y_DIMENSION, ybuf) ;
	}

			GetDlgItemText(hDlg, IDC_Y_DIMENSION, ybuf, 20) ;
			rsz_y = atoi(ybuf) ;

		}

		EndDialog(hDlg,IDOK) ;

		break ;

	case IDCANCEL:
		EndDialog(hDlg,IDCANCEL) ;
		break ;

	default:
		break ;
	} // switch (wParam)
	break ; // end case WM_COMMAND:


   }	// switch (msg)


		return FALSE ;
}

BOOL CALLBACK SelCaptDriverDlg(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	switch(msg)
	{
	case WM_INITDIALOG:
		return TRUE;

	case WM_COMMAND:
		switch(wParam)
		{
			int sel ;
		case IDB_B_SELCAPTDRIVER:
			sel = 0;
			SendMessage(hDlgCaptDriver_List, LB_GETSELITEMS, 1, sel) ;
			SendMessage(hWndGrb, WM_CAP_DRIVER_CONNECT, sel, 0L) ;
			SendMessage(hDlgCaptDriver, WM_CLOSE, 0, 0L) ;
			SendMessage(hWndGrb, WM_CAP_DRIVER_GET_CAPS, sizeof(CAPDRIVERCAPS),(LONG)(LPVOID)&CapDrvCaps) ;
			capPreviewRate(hWndGrb, 66) ;
			capPreview(hWndGrb,TRUE) ;
		}
		return TRUE ;

		case WM_CLOSE:
			DestroyWindow(hDlgCaptDriver) ;
			return TRUE;
	}

	return (0L) ;
}

int EnumCapDrv() // enumerate the installed capture drivers
{
	char szDeviceName[80]; // driver name
	char szDeviceVersion[80]; // driver version
	char item[161]; // concatinated string
	int i; // counter

	for (i=0; i<10; i++)
	{
		if ( capGetDriverDescription(i, szDeviceName, sizeof(szDeviceName),
									szDeviceVersion, sizeof(szDeviceVersion)) )
		{
				strcpy(item, szDeviceName);
				strcat(item, " ");
				strcat(item, szDeviceVersion);
		
				// add item to list box
				SendMessage(hDlgCaptDriver_List, LB_ADDSTRING, 0, 
            			   (LPARAM) item);
            	SendMessage(hDlgCaptDriver_List, LB_SETITEMDATA, i, (LPARAM) i);
        }
    }
    
    return 0;
}

BOOL CALLBACK GrabSetUpDlg(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static HWND UDGrbMn,  EDGrbMn ;
	static HWND UDGrbSc,  EDGrbSc ;
	static HWND SelBtn ;
	       BOOL err ;

	switch(msg)
	{

case WM_INITDIALOG:
	UDGrbMn  = GetDlgItem(hDlg,IDC_U_GRAB_MINUTES) ;
	EDGrbMn  = GetDlgItem(hDlg,IDC_E_GRAB_MINUTES) ;
	UDGrbSc  = GetDlgItem(hDlg,IDC_U_GRAB_SECONDS) ;
	EDGrbSc  = GetDlgItem(hDlg,IDC_E_GRAB_SECONDS) ;

	SetUDRng(UDGrbMn,   MaxGrbIval, 0) ; // two hours maximum standard default, but settable up to 24 hours in Preferences
	SetUDPos(UDGrbMn,   0) ;
	SetUDRng(UDGrbSc,   59, 0) ;
	SetUDPos(UDGrbSc,   5) ;

	SetDlgItemText(hDlg, IDC_E_PREFIX,    GrabPrefix) ; 
	SetDlgItemText(hDlg, IDC_E_SEND_TO,      GrabDir) ;
	
	SetDlgItemInt(hDlg,  IDC_E_GRAB_SECONDS, 5, FALSE) ; 
	SetDlgItemInt(hDlg,  IDC_E_GRAB_MINUTES, 0, FALSE) ;
	
	CheckRadioButton(hDlg,
					IDC_R_GMT,
					IDC_R_LOCAL,
					IDC_R_LOCAL) ;

	UseLocalTime = 1 ;
	    RotateCW = RotateACW = 0 ;

		 if (grabbeeps)
			 CheckDlgButton(hDlg, IDC_C_BEEPS, 1) ;

		 SendDlgItemMessage(hDlg,
			 IDC_B_GRAB_START,
			 WM_SETTEXT,
			 (WPARAM)0,
			 (LPARAM)(LPCTSTR)grabgo[0]) ;

		 SendDlgItemMessage(hDlg,
			 IDC_B_GRAB_TO_FILE,
			 WM_SETTEXT,
			 (WPARAM)0,
			 (LPARAM)(LPCTSTR)filego[0]) ;

		if (!hWndGrb) // create capture window if it's not yet created.
		{
			hWndGrb = capCreateCaptureWindow
				(
					"Big Deal",
					WS_CHILD|WS_VISIBLE,
					16,16,
					640,480,
					(HWND)hDlg,
					(int)1
				) ;
		}

	return TRUE ;

case WM_COMMAND:

		switch(HIWORD(wParam)) // notifications
		{
		case EN_CHANGE: // an edit box has been edited

			switch(LOWORD(wParam)) // which one?
			{
			case IDC_E_SEND_TO:
				GetDlgItemText(hDlg, IDC_E_SEND_TO, GrabDir, 256) ;
				break ;

			case IDC_E_PREFIX:
				GetDlgItemText(hDlg, IDC_E_PREFIX, GrabPrefix, 80) ;
				break ;

			case IDC_E_GRAB_SECONDS:
				GrabSecs = GetDlgItemInt(hDlg,IDC_E_GRAB_SECONDS, &err, FALSE) ;
				break ;

			case IDC_E_GRAB_MINUTES:
				GrabMins = GetDlgItemInt(hDlg,IDC_E_GRAB_MINUTES, &err, FALSE) ;
				break ;

			default:
				break ;
			} // switch (LOWORD(wParam))

			break ;// EN_CHANGE

		default:
			break ;
		}// switch(HIWORD(wParam))

	switch(LOWORD(wParam))
	{
	case IDC_B_SELCAPTDRIVER:					// get the capture driver
		ShowWindow(hDlgCaptDriver, SW_SHOW) ;
		BringWindowToTop(hDlgCaptDriver) ;
		break ;

	case IDC_B_SOURCE:							// select the video source
		if (CapDrvCaps.fHasDlgVideoSource)
			capDlgVideoSource(hWndGrb);
		break ;

	case IDC_B_DEFAULT_GRAB_INTERVAL:			// use the default interval (5 seconds)
		SetDlgItemInt(hDlg,IDC_E_GRAB_MINUTES,0,FALSE) ;
		GrabMins = 0 ;
		SetDlgItemInt(hDlg,IDC_E_GRAB_SECONDS,5,FALSE) ;
		GrabSecs = 5 ;
		break ;

	case IDC_B_DEFAULT_DEST:					// use the default destination directory ("C:\Grabbed")
		SetDlgItemText(hDlg, IDC_E_SEND_TO, "C:\\Grabbed\\") ;
		GetDlgItemText(hDlg, IDC_E_SEND_TO, GrabDir, 256) ;
		break ;

	case IDC_B_DEFAULT_PREFIX:					// use the default file prefix ("Grab_")
		SetDlgItemText(hDlg, IDC_E_PREFIX, "Grab_") ;
		GetDlgItemText(hDlg, IDC_E_PREFIX, GrabPrefix, 80) ;
		break ;

	case IDC_B_GRAB_START:						// start/stop the timed grabs
		SendMessage(hWndCtrl, WM_COMMAND, IDM_M_GRAB, 0L) ; 
		break ;

	case IDC_B_ONESHOT:							// capture and save one frame
		GrabFrame() ;
		break ;

	case IDC_C_BEEPS:							// beep the captures
		grabbeeps = IsDlgButtonChecked(hDlg,IDC_C_BEEPS) ;
		break ;

	default:
		break ;
	} // switch (LOWORD(wParam))

	break ; // WM_COMMAND

	case WM_MOUSEMOVE:
		break ;

	case WM_LBUTTONDOWN:
		break ;

	case WM_LBUTTONUP:
		break ;

default:
	break ;
	} // switch (msg)

	return FALSE ;
}

BOOL CALLBACK PrefsDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static HWND UDSmooth, EDSmooth, hW ;
	static HWND UDGain,   EDGain ;
	static HWND UDThresh, EDThresh ;
	static HWND UDXStep,  EDXStep ;
	static HWND UDYStep,  EDYStep ;
	static HWND UDQual,   EDQual ;
	static HWND UDAlRes,  EDAlRes ;
	static HWND UDGrbInt, EDGrbInt ;

	char buff[20] ;

	switch(msg)
	{

case WM_INITDIALOG:

	UDSmooth = GetDlgItem(hDlg,IDC_SPIN_SMOOTH) ;
	EDSmooth = GetDlgItem(hDlg,IDC_SMOOTHING_LEVEL) ;
	UDGain   = GetDlgItem(hDlg,IDC_SPIN_LUM_GAIN) ;
	EDGain   = GetDlgItem(hDlg,IDC_DIFF_LUM_GAIN) ;
	UDThresh = GetDlgItem(hDlg,IDC_SPIN_LUM_THRESH) ;
	EDThresh = GetDlgItem(hDlg,IDC_DIFF_LUM_THRESH) ;
	UDXStep  = GetDlgItem(hDlg,IDC_SPIN_FAST_X_STEP) ;
	EDXStep  = GetDlgItem(hDlg,IDC_CUR_FAST_X_STEP) ;
	UDYStep  = GetDlgItem(hDlg,IDC_SPIN_FAST_Y_STEP) ;
	EDYStep  = GetDlgItem(hDlg,IDC_CUR_FAST_Y_STEP) ;
	UDQual   = GetDlgItem(hDlg,IDC_U_JPG_QUALITY) ;
	EDQual   = GetDlgItem(hDlg,IDC_E_JPG_QUALITY) ;
	UDAlRes  = GetDlgItem(hDlg,IDC_U_ALIGN_RESOLUTION) ;
	EDAlRes  = GetDlgItem(hDlg,IDC_E_ALIGN_RESOLUTION) ;
	UDGrbInt = GetDlgItem(hDlg,IDC_U_MAX_GRAB_INTERVAL) ; 
	EDGrbInt = GetDlgItem(hDlg,IDC_E_MAX_GRAB_INTERVAL) ;

	SetUDRng(UDSmooth, 10, 0) ;
	SetUDPos(UDSmooth, scansmooth) ;
	SetUDRng(UDGain,   512, 16) ;
	SetUDPos(UDGain,   diffgain) ;
	SetUDRng(UDThresh, THMAX, 0) ;
	SetUDPos(UDThresh, threshold) ;
	SetUDRng(UDXStep,  20, 0) ;
	SetUDPos(UDXStep,  Xnudge) ;
	SetUDRng(UDYStep,  20, 0) ;
	SetUDPos(UDYStep,  Ynudge) ;
	SetUDRng(UDQual,   100, 1) ;
	SetUDPos(UDQual,   JPGQuality) ;
	SetUDRng(UDAlRes,  1000, 0) ;
	SetUDPos(UDAlRes,  (UINT)(AlignResolution * 100.0)) ;
    SetUDRng(UDGrbInt, MaxGrbIntLimit, 0) ;
	SetUDPos(UDGrbInt, MaxGrbIval) ;

	sprintf(buff,"%3.2f", AlignResolution) ;
	SetDlgItemText(hDlg, IDC_E_ALIGN_RESOLUTION, buff) ;

	sprintf(buff, "%d", MaxGrbIval) ;
	SetDlgItemText(hDlg, IDC_E_MAX_GRAB_INTERVAL, buff) ;

		 if (autoMax)
			 CheckDlgButton(hDlg,IDC_AUTOMAX,1) ;
		 if (autoRes)
			 CheckDlgButton(hDlg,IDC_AUTORES,1) ;
		 if (invert)
			 CheckDlgButton(hDlg,IDC_INV_DRAW,1) ;
		 if (sounds)
			 CheckDlgButton(hDlg,IDC_SOUNDS,1) ;
		 if (showtips)
			 CheckDlgButton(hDlg,IDC_SHOW_TIPS,1) ;
		 if (showPC)
			 CheckDlgButton(hDlg,IDC_SHOW_PC,1) ;
		 if (matchbend)
			 CheckDlgButton(hDlg,IDC_SNAP_PC,1) ;
		 if (PermitOverRideOnNew)
			 CheckDlgButton(hDlg,IDC_C_OVER_RIDE,1) ;
		 if (!noselect)
			 CheckDlgButton(hDlg,IDC_C_ARCHIVED_CROP,1) ;
		 if (AskIfToSave)
			 CheckDlgButton(hDlg,IDC_C_ASKTOSAVE,1) ;
		 if (NoHorizontal)
			 CheckDlgButton(hDlg,IDC_C_NO_HORIZ,1) ;
		 if (showJPGtext)
			 CheckDlgButton(hDlg,IDC_C_SHOW_JPG_TEXTS,1) ;

	return TRUE ;
	break ;

case WM_VSCROLL:

	    hW = (HWND)lParam ;

			if (hW == UDSmooth)
			{
				SendMessage
				   (
					EDSmooth,
					WM_GETTEXT,
					20,
				   (LPARAM)buff
				   ) ;
				scansmooth = atoi(buff) ;
				ShowSmoothing(hWndScan) ;
			}

			if (hW == UDGain)
			{
				SendMessage
				   (
					EDGain,
					WM_GETTEXT,
					20,
				   (LPARAM)buff
				   ) ;
				diffgain = atoi(buff) ;
			}

			if (hW == UDThresh)
			{
				SendMessage
				   (
					EDThresh,
					WM_GETTEXT,
					20,
				   (LPARAM)buff
				   ) ;
				threshold = atoi(buff) ;
			}

			if (hW == UDXStep)
			{
				SendMessage
				   (
					EDXStep,
					WM_GETTEXT,
					20,
				   (LPARAM)buff
				   ) ;
				Xnudge = atoi(buff) ;
			}

			if (hW == UDYStep)
			{
				SendMessage
				   (
					EDYStep,
					WM_GETTEXT,
					20,
				   (LPARAM)buff
				   ) ;
				Ynudge = atoi(buff) ;
			}

			if (hW == UDQual)
			{
				SendMessage
				   (
					EDQual,
					WM_GETTEXT,
					20,
				   (LPARAM)buff
				   ) ;
				JPGQuality = atoi(buff) ;
			}

			if (hW == UDAlRes)
			{
				AlignResolution = (double)GetUDPos(hW) / 100.0 ;
				sprintf(buff, "%3.2f", AlignResolution) ;
				SetDlgItemText(hDlg, IDC_E_ALIGN_RESOLUTION, buff) ;
			}

			if (hW == UDGrbInt)
			{
				SendMessage
				   (
					EDGrbInt,
					WM_GETTEXT,
					20,
				   (LPARAM)buff
				   ) ;
				MaxGrbIval = atoi(buff) ;
				SetUDPos(UDGrbInt, MaxGrbIval) ;
			}

			break ;

case WM_COMMAND:
	switch(LOWORD(wParam))
	{

	case IDC_CUR_DEF_X_STEP:
		SetDlgItemInt(hDlg,IDC_CUR_FAST_X_STEP,6,TRUE) ;
		Xnudge = 6 ;
		break ;

	case IDC_CUR_DEF_Y_STEP:
		SetDlgItemInt(hDlg,IDC_CUR_FAST_Y_STEP,6,TRUE) ;
		Ynudge = 6 ;
		break ;

	case IDC_B_DEFAULT_JPG:
		SetDlgItemInt(hDlg,IDC_E_JPG_QUALITY,64,TRUE) ;
		JPGQuality = 64 ;
		break ;

	case IDC_B_DEFAULT_GRAB:
		SetDlgItemInt(hDlg,IDC_E_MAX_GRAB_INTERVAL,120,TRUE) ;
		MaxGrbIval = 120 ;
		break ;

	case IDC_E_ALIGN_RESOLUTION:
		GetDlgItemText(hDlg, IDC_E_ALIGN_RESOLUTION, buff, 20) ;
		AlignResolution = atof(buff) ;
		SetUDPos(UDAlRes, (UINT)(100.0 * AlignResolution)) ;
		break ;

	case IDC_B_DEFAULT_ALIGNRES:
		AlignResolution = 0.04 ;
		sprintf(buff,"%3.2f", AlignResolution) ;
		SetDlgItemText(hDlg, IDC_E_ALIGN_RESOLUTION, buff) ;
		SetUDPos(UDAlRes, (UINT)(100.0 * AlignResolution)) ;
		break ;

	case IDC_E_MAX_GRAB_INTERVAL:
		GetDlgItemText(hDlg, IDC_E_MAX_GRAB_INTERVAL, buff, 20) ;
		break ;

	case IDOK:
 		    autoRes = IsDlgButtonChecked(hDlg,IDC_AUTORES) ;
			 invert = IsDlgButtonChecked(hDlg,IDC_INV_DRAW) ;
			autoMax = IsDlgButtonChecked(hDlg,IDC_AUTOMAX) ;
			 sounds = IsDlgButtonChecked(hDlg,IDC_SOUNDS) ;
		   showtips = IsDlgButtonChecked(hDlg,IDC_SHOW_TIPS) ;
		     showPC = IsDlgButtonChecked(hDlg,IDC_SHOW_PC) ;
		  matchbend = IsDlgButtonChecked(hDlg,IDC_SNAP_PC) ;
PermitOverRideOnNew = IsDlgButtonChecked(hDlg,IDC_C_OVER_RIDE) ;
	       noselect =!IsDlgButtonChecked(hDlg,IDC_C_ARCHIVED_CROP) ;	// Note the negative
	    AskIfToSave = IsDlgButtonChecked(hDlg,IDC_C_ASKTOSAVE) ;
	   NoHorizontal = IsDlgButtonChecked(hDlg,IDC_C_NO_HORIZ) ;
	    showJPGtext = IsDlgButtonChecked(hDlg,IDC_C_SHOW_JPG_TEXTS) ;	// sequentially display texts embedded in JPG

			 if (sounds)   // tell the button
				VOC = 1 ;
		        else
				VOC = 0 ;
		   ivrc(hWndCtrl,&rctl[Voc],TRUE) ;
		   UpdateWindow(hWndCtrl) ;

		   ivrc(hWndRslt,NULL,TRUE) ;
		   UpdateWindow(hWndRslt) ;

			 EndDialog(hDlg,IDOK) ;
			 break ;

	case IDCANCEL:
		EndDialog(hDlg,IDCANCEL) ;
		break ;

	default:
		break ;
	} // switch (wParam)

	break ; // end case WM_COMMAND:

default:
	break ;
	} // switch(msg)

	return FALSE ;
}

BOOL CALLBACK TkParmDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static HWND UDSmooth, UDSpan, UDThresh, UDRate, UDJump, UDGain, hW ;
	static HWND EDSmooth, EDSpan, EDThresh, EDRate, EDJump, EDGain ;
	BOOL snafu ;

	switch(msg)
	{

case WM_INITDIALOG:

	UDSmooth = GetDlgItem(hDlg,IDC_SPIN_SMOOTHING) ;
	UDSpan   = GetDlgItem(hDlg,IDC_SPIN_SPAN) ;
	UDThresh = GetDlgItem(hDlg,IDC_SPIN_THRESH) ;
	UDRate   = GetDlgItem(hDlg,IDC_U_TRACK_RATE) ;
	UDJump   = GetDlgItem(hDlg,IDC_U_JUMP_SIZE) ;
	UDGain   = GetDlgItem(hDlg,IDC_U_DIFFGAIN) ;

	EDSmooth = GetDlgItem(hDlg,IDC_GRAPH_SMOOTHING) ;
	EDSpan   = GetDlgItem(hDlg,IDC_SEEK_SPAN) ;
	EDThresh = GetDlgItem(hDlg,IDC_THRESH) ;
	EDRate   = GetDlgItem(hDlg,IDC_E_TRACK_RATE) ;
	EDJump   = GetDlgItem(hDlg,IDC_E_JUMP_SIZE) ;
	EDGain   = GetDlgItem(hDlg,IDC_E_DIFFGAIN) ;

	SetUDRng(UDSmooth,  10,   0) ;
	SetUDRng(UDSpan,    30,   0) ;
	SetUDRng(UDThresh, THMAX, 0) ;
	SetUDRng(UDRate,   100,   2) ;
	SetUDRng(UDJump,    20,   1) ;
	SetUDRng(UDGain,   512,  16) ;

	SetDlgItemInt(hDlg,IDC_GRAPH_SMOOTHING, scansmooth,  FALSE) ;
	SetDlgItemInt(hDlg,IDC_SEEK_SPAN,       seekspan,    FALSE) ;
	SetDlgItemInt(hDlg,IDC_THRESH,          threshold,   FALSE) ;
	SetDlgItemInt(hDlg,IDC_E_TRACK_RATE,    SelfTrkRate, FALSE) ;
	SetDlgItemInt(hDlg,IDC_E_JUMP_SIZE,     jumpsize,    FALSE) ;
	SetDlgItemInt(hDlg,IDC_E_DIFFGAIN,      diffgain,    FALSE) ;

	SetUDPos(UDSpan,   seekspan) ;
	SetUDPos(UDSmooth, scansmooth) ;
	SetUDPos(UDThresh, threshold) ;
	SetUDPos(UDRate,   SelfTrkRate) ;
	SetUDPos(UDJump,   jumpsize) ;
	SetUDPos(UDGain,   diffgain) ;

	return TRUE ;
	break ;

       case WM_VSCROLL:

			hW = (HWND)lParam ;

			if (hW == UDSmooth)
			{
	scansmooth = GetUDPos(UDSmooth) ;
	SetDlgItemInt(hDlg,IDC_GRAPH_SMOOTHING,scansmooth,FALSE) ;
	SendMessage(hWndScan, WM_COMMAND, SCROLLS,0L) ;
	ShowSmoothing(hWndScan) ;
			}

			if (hW == UDSpan)
			{
    seekspan = GetUDPos(UDSpan) ;
	SetDlgItemInt(hDlg,IDC_SEEK_SPAN,seekspan,FALSE) ;
			}

			if (hW == UDThresh)
			{
    threshold = GetUDPos(UDThresh) ;
	SetDlgItemInt(hDlg,IDC_THRESH,threshold,FALSE) ;
	SendMessage(hWndScan, WM_COMMAND, SCROLLS,0L) ;
			}

			if (hW == UDRate)
			{
    SelfTrkRate = GetUDPos(UDRate) ; 
	SetDlgItemInt(hDlg,IDC_E_TRACK_RATE,SelfTrkRate,FALSE) ;
			}

			if (hW == UDJump)
			{
    jumpsize = GetUDPos(UDJump) ;
	SetDlgItemInt(hDlg,IDC_E_JUMP_SIZE,jumpsize,FALSE) ;
			}

			if (hW == UDGain)
			{
    diffgain = GetUDPos(UDGain) ;
	SetDlgItemInt(hDlg,IDC_E_DIFFGAIN,diffgain,FALSE) ;
	SendMessage(hWndScan, WM_COMMAND, SCROLLS,0L) ;
			}

			break ;


case WM_COMMAND:

	switch(HIWORD(wParam)) // pick up notifications
	{
	case EN_CHANGE:        // an edit box has changed

		switch(LOWORD(wParam)) // which one?
		{

	case IDC_GRAPH_SMOOTHING:
		scansmooth =
		GetDlgItemInt(hDlg, IDC_GRAPH_SMOOTHING, &snafu, FALSE) ;
        SetUDPos(UDSmooth, scansmooth) ;
	    SendMessage(hWndScan, WM_COMMAND, SCROLLS,0L) ;
		ShowSmoothing(hWndScan) ;
		break ;

	case IDC_SEEK_SPAN:
		seekspan =
		GetDlgItemInt(hDlg, IDC_SEEK_SPAN,       &snafu, FALSE) ;
        SetUDPos(UDSpan, seekspan) ;
		break ;

	case IDC_THRESH:
		threshold =
		GetDlgItemInt(hDlg, IDC_THRESH,          &snafu, FALSE) ;
		SetUDPos(UDThresh, threshold) ;
    	SendMessage(hWndScan, WM_COMMAND, SCROLLS, 0L) ;
		break ;

	case IDC_E_TRACK_RATE:
		SelfTrkRate =
		GetDlgItemInt(hDlg, IDC_E_TRACK_RATE,    &snafu, FALSE) ;
	    SetUDPos(UDRate, SelfTrkRate) ;
		break ;

	case IDC_E_JUMP_SIZE:
		jumpsize =
		GetDlgItemInt(hDlg, IDC_E_JUMP_SIZE,     &snafu, FALSE) ;
		SetUDPos(UDJump, jumpsize) ;
		break ;

	case IDC_E_DIFFGAIN:
		diffgain =
		GetDlgItemInt(hDlg, IDC_E_DIFFGAIN,     &snafu, FALSE) ;
		SetUDPos(UDGain, diffgain) ;
    	SendMessage(hWndScan, WM_COMMAND, SCROLLS, 0L) ;
		break ;

	default:
		break ;

		} // end switch (LOWORD(wParam))

		break ; // break for case EN_CHANGE:

  default:
		break ;
	} // end switch (HIWORD(wParam))

	break ; // end case WM_COMMAND:

   }	// end switch (msg)

		return FALSE ;
}

int MakeRoom( void )
{
			// Allocate storage for results
					if (hResults != (HGLOBAL)NULL) GlobalFree(hResults) ;
				        hResults  = GlobalAlloc(GPTR, sizeof (BUDRESULTS)) ;
			
		    // Allocate storage for measure grid
				   if (hMeasure != (HGLOBAL)NULL) GlobalFree(hMeasure) ;
				       hMeasure  = GlobalAlloc(GPTR, sizeof (MEASURE)) ;

					  if
					   (
						hResults == (HGLOBAL)NULL ||
						hMeasure == (HGLOBAL)NULL
					   )
					    {
						  char st[100] ;
						  sprintf(st,
							     "Storage Allocation has Failed.\n\n" \
								 "Shutting Down the Bud Workshop.") ;

						  MessageBox(NULL,st,
							             "Memory Allocation for Results",
										  MB_ICONEXCLAMATION|MB_OK) ;
						  return 0 ;
					    }

					 pBudResults = (LPBUDRESULTS)hResults ;
					    pMeasure = (LPMEASURE)hMeasure ;

						  return 1 ;
}

void SaveAllAway( void )
 {
	char str[100] ; int t = 0 ;
				if (gotimage)  // This is the INCUMBENT image
				{			       // i.e., an image still in work.
				 if (StandardBudImage) // is properly named?
				 {
			// save the current states
				 SaveIniFile(1, I) ;   // The INI is saved as usual

				 if (!hasDATinfo && useDATs)	// if we DONT have the DAT's info in the INI, and are using DATs
			     SaveDatFile(1, I) ;			//  Keep the DAT and save to it.
				 else
				 if (useDATs && haveOldDAT) // we do have the info in the INI and still have the DAT - sequester it!
				 {
					 char sznewfile[255] ;
					 char  sznewdir[255] ;
					 strcpy(sznewfile, "C:\\DatGrave") ;
					 strcat(sznewfile, szCurrentSuite) ;
					 strcpy(sznewdir,  sznewfile) ;
					 _mkdir(sznewdir) ;
					 strcat(sznewfile, szDatFile) ;

					 t = t ;  //dummy op for breakpoint mkdir

					 rename(szDatPath, sznewfile) ; // this should move the DAT _out_ of the Archive.
					 Note (1,"DAT Moved") ;
				 }
				 if (autotracked)				// save the TRK as usual
				 SaveTrkFile(&Tk, 1, I) ;
				 sprintf(str, "  Instance %s Archived. ", DropExt(DropPath(szArchFile))) ;
				  Note(1, str) ;
				 }
				}
 }

void Note(int timer, char * m )
{
				  HDC hdc ;
				 SIZE  sz ;
				 RECT  rc ;
				HFONT  oF ;
				  int len ;

				 if ( timer )
				 SetTimer(hWndCtrl, IDT_DISMISS, 1000, NULL) ;
				 else
				 KillTimer(hWndCtrl, IDT_DISMISS) ;

				 hdc = GetDC(hWndCtrl) ;
				 oF = SelectObject(hdc, hfnt2) ;
				 GetClientRect(hWndCtrl, &rc) ;

				 ivrc(hWndCtrl, &rctxt, TRUE) ;
				 UpdateWindow(hWndCtrl) ;

				 GetTextExtentPoint32(hdc, m, len = strlen(m), &sz) ;
				 SetRect(&rctxt, rc.right - (sz.cx + 10), rc.top + sz.cy, rc.right, rc.top + 2 * sz.cy) ;
				 TextOut(hdc, rc.right - (sz.cx + 10), rc.top + sz.cy, m, len) ;
				 SelectObject(hdc, oF) ;
				 ReleaseDC(hWndCtrl, hdc) ;
}

int incpth( char * c )
{
	A.iGpthIDs++ ;
	if ((MAXPTHS - A.iGpthIDs) < 10)
		MessageBox(NULL, c, "Near Paths Limit!", MB_OK) ;
	return A.iGpthIDs ;
}

BOOL CALLBACK PickArcDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	int i ;

	switch(msg)
	{
case WM_INITDIALOG:

	ClearCombo(hDlg, IDC_CB_SEL_ARCHIVE) ;

	for (i = 0 ; i < A.iArcs ; i++)
	InsInCombo(hDlg, IDC_CB_SEL_ARCHIVE, A.szKnownArc[i], i) ;
	return TRUE ;

case WM_COMMAND:

	switch(LOWORD(wParam))
	{
		/*
	case IDC_CB_SEL_ARCHIVE:

		SendDlgItemMessage(hDlg,
						   IDC_CB_SEL_ARCHIVE,
						   WM_GETTEXT,
						   (WPARAM)256,
						   (LPARAM)szUsingArchive) ;
		break ;
		*/

	case IDOK:
		SendDlgItemMessage(hDlg,
						   IDC_CB_SEL_ARCHIVE,
						   WM_GETTEXT,
						   (WPARAM)256,
						   (LPARAM)szUsingArchive) ;
		EndDialog(hDlg, IDOK) ;
		break ;

	case IDCANCEL:
		EndDialog(hDlg, IDCANCEL) ;
		break ;

	default:
		break ;
	} // switch (LOWORD(wParam))

	break ; // for WM _COMMAND
	}	// switch (msg)

return FALSE ;
} 

BOOL CALLBACK PickSuiteDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	    int i ;
	LPSUITE ps ;
	int PfxStyle ;

	switch(msg)
	{
case WM_INITDIALOG: // dialog is modal, so this acts on every access

	ClearCombo(hDlg, IDC_CB_SLCT_SUITE) ; // clear the list

	// select BudPfxID   if opening an instance for work of a bud from a suite of a prefix.
	// select CurrentPfxID if working with the whole series in a suite.

	PfxStyle = IsInst? BudPfxID : CurrentPfxID ;

	for (i = 0 ; i < A.iNumsuiperpfx[PfxStyle] ; i++) // fill combo list with the suites for the prefix
	{
		ps = A.pSuiteperpfx[PfxStyle][i] ;
		InsInCombo(hDlg, IDC_CB_SLCT_SUITE, ps->desc, i) ; // the combo index is equal to the Suite's ID
	}
	
	// select first suite in list into edit box by default
		ps = A.pSuiteperpfx[PfxStyle][0] ;
		PutCBEdBox(hDlg, IDC_CB_SLCT_SUITE, ps->desc) ;

	return TRUE ;

case WM_COMMAND:

	switch(LOWORD(wParam))
	{
	case IDC_CB_SLCT_SUITE:
	OldSuite = UseSuite ;
	UseSuite = SendDlgItemMessage(hDlg,
					IDC_CB_SLCT_SUITE,
					CB_GETCURSEL,		//the Suite's ID is equal to the combo index
					(WPARAM)0,
					(LPARAM)0) ;
		break ;

	case IDOK:
		EndDialog(hDlg, IDOK) ;
		break ;

	case IDCANCEL:
		break ;
	default:
		break ;
	} // switch (LOWORD(wParam))
	break ; // WM _COMMAND
  }	// switch (msg)
return FALSE ;
}

BOOL CALLBACK SearchStatsDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	switch(msg)
	{
case WM_INITDIALOG:
	return TRUE ;

case WM_COMMAND:

	switch(LOWORD(wParam))
	{

	default:
		break ;
	} // switch (LOWORD(wParam))

	break ; // WM _COMMAND

  }	// switch (msg)
return FALSE ;
}

void clear(void)
{
	int i ;
                 // are we showing lines scan graphs? Turn 'em off!
				 if (graphing)
				 SendMessage(hWndBud,WM_COMMAND,TOGGLE_GRAPHS,0L) ;
				// are we scanning? Stop scanning!
				 if (scanning)
				 SendMessage(hWndBud,WM_COMMAND,TOGGLE_SCAN,0L) ;
 
			// get rid of any old differential luminance maxima
			for ( i = 0 ; i < nPeaks ; i++ ) PeakAt[i] = PeakVal[i] = 0 ;
							       nPeaks = 0 ;
			// set all level-measurement indicators to none done
			// set all measurement styles to none
			for ( i = 1 ; i <= MAXLEVELS ;
			              LEdgeOrg[i] = REdgeOrg[i] = EdgeDone[i++] = NONE) ;

			// set all mid pts and axis radii to nil
			for ( i = 1 ; i <= MAXLEVELS ; 
			       AxisRadius[i] = MidPt[i].x = MidPt[i++].y = 0.0) ;

			// set the parms of the trial Path Curve to defaults
			    TrialLam = 2.0 ;
			    TrialRad = 0.25 ;

					// if we have autotracked, cancel it
					if (autotracked)
					{
				   autotracked = autotrack = AUT = 0 ;
					 ivrc(hWndBud,&rctl[Aut],FALSE) ;
				   autolftdone = ALF = 0 ;
					 ivrc(hWndBud,&rctl[Alf],FALSE) ;
				   autorytdone = ART = 0 ;
					 ivrc(hWndBud,&rctl[Art],FALSE) ;
					}
}

/* clean and prepare the stable */
void tabularasa( void )
{
                 calibrating = calibrated = reset ;
			              CAL_1_AVAILABLE = reset ;
			              CAL_2_AVAILABLE = reset ;
				   ResetCalibration() ;
				    scanning =   setlevels = reset ;
		             resized =     setpole = reset ;
					  TOPSET =      BOTSET = reset ;
					 AllDone =    SomeDone = reset ;
			   GrowthMeasure = FracChanged = reset ;
			    UsingDefault = 1 ;
				  scancolour = 0 ; // default to all colours

			// Supply default positions for the poles
			// and use the most recent set of levels
			// to give MeasureGrid() something
			// with which to work for the time being

				pMeasure->iTopPole.x = TPxdefault ;
				pMeasure->iTopPole.y = TPydefault ;
				pMeasure->iBotPole.x = BPxdefault ;
				pMeasure->iBotPole.y = BPydefault ;

			//and set up a grid

				MeasureGrid(pMeasure) ;

			// set magnification to 1.0 and the number of levels to
			// the current default

				pBudResults->BudMag    = pmag = 1.0 ;
				pBudResults->NumHyts   = Levels ;
}

void convertDAT(void)
{
		  LPBUDRESULTS  B ;
		     LPMEASURE  M ;
		 LPOBUDRESULTS OB ;
		    LPOMEASURE OM ;
		          int  g ;

				pOBudResults  = (LPOBUDRESULTS)GlobalAlloc(GPTR, sizeof(OBUDRESULTS)) ;
				   pOMeasure  = (LPOMEASURE)GlobalAlloc(GPTR, sizeof(OMEASURE)) ;

				   OB = pOBudResults ;
				   OM = pOMeasure ;
				    B = pBudResults ;
				    M = pMeasure ;

				ReadDatFile(1) ; // read in old format

		  // convert to new format.
	      strcpy(pBudResults->BudSpecTxt,      OB->BudSpecTxt) ; 
		  strcpy(pBudResults->BudPlaceTxt,     OB->BudPlaceTxt) ;  
		  strcpy(pBudResults->BudLatitudeTxt,  OB->BudLatitudeTxt) ;	 
		  strcpy(pBudResults->BudLongitudeTxt, OB->BudLongitudeTxt) ;
		  strcpy(pBudResults->BudImageFile,    OB->BudImageFile) ;
		  strcpy(pBudResults->BudDataFile,     OB->BudDataFile) ;
		  strcpy(pBudResults->BudTextFile,     OB->BudTextFile) ;
		  strcpy(pBudResults->BudDateTxt,      OB->BudDateTxt) ;
		  strcpy(pBudResults->BudTimeTxt,      OB->BudTimeTxt) ;
		  pBudResults->NumHyts   = OB->NumHyts ;
		  pBudResults->SubImageX = OB->SubImageX ;		    
		  pBudResults->SubImageY = OB->SubImageY ; 
		  pBudResults->SubImageW = OB->SubImageW ;
		  pBudResults->SubImageH = OB->SubImageH ;

		  for (g = 1 ; g <= OMAXLEVELS ; g++)
		  pBudResults->Edges[g]  = OB->Edges[g] ;

		pBudResults->BudMag      = OB->BudMag ;
	    pBudResults->BudLength   = OB->BudLength ;
		pBudResults->BudTilt     = OB->BudTilt ;
		pBudResults->BudTopPoleX = OB->BudTopPoleX ;	    
		pBudResults->BudTopPoleY = OB->BudTopPoleY ;
		pBudResults->BudBotPoleX = OB->BudBotPoleX ;
		pBudResults->BudBotPoleY = OB->BudBotPoleY ;

		pBudResults->LeftProjLambda  = OB->LeftProjLambda ;
		pBudResults->LeftProjMRD     = OB->LeftProjMRD ;
		pBudResults->LeftRegrLambda  = OB->LeftRegrLambda ;
		pBudResults->LeftRegrMRD     = OB->LeftRegrMRD ;

		pBudResults->RightProjLambda = OB->RightProjLambda ;
		pBudResults->RightProjMRD    = OB->RightProjMRD ;
		pBudResults->RightRegrLambda = OB->RightRegrLambda ;
		pBudResults->RightRegrMRD    = OB->RightRegrMRD ;

		pBudResults->DiamProjLambda  = OB->DiamProjLambda ;
	    pBudResults->DiamProjMRD     = OB->DiamProjMRD ;
		pBudResults->DiamRegrLambda  = OB->DiamRegrLambda ;
		pBudResults->DiamRegrMRD     = OB->DiamRegrMRD ;

		for ( g = 1 ; g <= OMAXLEVELS ; g++ )
		{
		    pBudResults->RProjDev[g] = OB->RProjDev[g] ;
		    pBudResults->LProjDev[g] = OB->LProjDev[g] ;
		    pBudResults->BProjDev[g] = OB->BProjDev[g] ;
		    pBudResults->RRegrDev[g] = OB->RRegrDev[g] ;
	 	    pBudResults->LRegrDev[g] = OB->LRegrDev[g] ;
		    pBudResults->BRegrDev[g] = OB->BRegrDev[g] ;
		}

		    pBudResults->RProjBestAt = OB->RProjBestAt ;
		    pBudResults->LProjBestAt = OB->LProjBestAt ;
		    pBudResults->BProjBestAt = OB->BProjBestAt ;
		    pBudResults->RRegrBestAt = OB->RRegrBestAt ;
		    pBudResults->LRegrBestAt = OB->LRegrBestAt ;
		    pBudResults->BRegrBestAt = OB->BRegrBestAt ;

		 pBudResults->RightRegrCoeff = OB->RightRegrCoeff ;
		 pBudResults->LeftRegrCoeff  = OB->LeftRegrCoeff ;
		 pBudResults->BothRegrCoeff  = OB->BothRegrCoeff ;


	   M->iTopPole.x       = OM->iTopPole.x ;
	   M->iTopPole.y       = OM->iTopPole.y ;
	   M->iBotPole.x       = OM->iBotPole.x ;
	   M->iBotPole.y       = OM->iBotPole.y ;
	   M->iAxisGradIcept.x = OM->iAxisGradIcept.x ;
	   M->iAxisGradIcept.y = OM->iAxisGradIcept.y ;

	for ( g = 1 ; g <= OMAXLEVELS ; g++ )
	{
    M->iAxisCuts[g].x      = OM->iAxisCuts[g].x ;
    M->iAxisCuts[g].y      = OM->iAxisCuts[g].y ;
	M->iLevGradIcepts[g].x = OM->iLevGradIcepts[g].x ;
	M->iLevGradIcepts[g].y = OM->iLevGradIcepts[g].y ;
	M->iLeftCut[g].x       = OM->iLeftCut[g].x ;
	M->iLeftCut[g].y       = OM->iLeftCut[g].y ;
	M->iRightCut[g].x      = OM->iRightCut[g].x ;
	M->iRightCut[g].y      = OM->iRightCut[g].y ;
	M->iLeftRad[g]         = OM->iLeftRad[g] ;
	M->iRightRad[g]        = OM->iRightRad[g] ;
	M->iDiameter[g]        = OM->iDiameter[g] ;
	}

				GlobalFree(pOBudResults) ;
				GlobalFree(pOMeasure) ;
}

/***********************************************************
							ProcessDIB

This function goes into action after an instance image has loaded.
 It initiates or continues interactive processing of instances,
				and works with the archive.

						16/09/2010
  Efforts are under way to be rid of the per-instance DATS,
  as the speed of computing these days has removed their
  original raison d'etre (to speed archive interaction), and
  there are now annoying compatibility issues.
   
 ***********************************************************/
void ProcessDIB ( void ) 
{
	        int i, k, ImgDimsDiffer ;
		    int recordedwid ;
		    int recordedhyt ;
	   OFSTRUCT of;
	static char buff[255] = "\0" ;
	static char f[256] ;
	static char mismatch[255] = "\0" ;
	static char warning[256] = "\0" ;

	static char MsgTxt[] = " is not a Standard Bud Image.\nIt will be excluded from the records." ;
	static char szFind[255] ;		// ToFind-string
		 double eptmp, epcrit, epdone, epwritten ;
		   long bfile, filesize ;
		 struct _finddata_t finfo ;
		   BOOL BL ;
		   char sbuff[30], fday[30], fmon[30], fyr[30], more[255], num[20] ;
	static char * mon[] =
		  {"Jan", "Feb", "Mar", "Apr", "May", "Jun",
		   "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"} ;
	
	LPMEASURE M ;
	LPBUDRESULTS B ;
					M = pMeasure ;
					B = pBudResults ;

				// ********* Initialise **********

			// if no image has been in work, then the incoming bud
			// is the first in the current session. Storage will
			// be needed for Results. If there has been a bud in
			// work, then no new storage is needed. Shut down if
			// allocation fails.
			if (!gotimage ) {
				if (!MakeRoom()) SendMessage(hWndCtrl,WM_DESTROY,0,0L) ; 
			                }
			// set all storage to null.
					memset(pBudResults,'\0',sizeof(struct tagBUDRESULTS)) ;
					memset(pMeasure,   '\0',sizeof(struct tagMEASURE)) ;

			// Experimental: preset inclusion of all levels in Lambda calculation
			for ( i = 0 ; i <= MAXLEVELS ; IncludeLev[i++] = 1) ;

			// but if we have an image already loaded, we want to offload it
			if (gotimage) // an incumbent!!!
				clear() ;

		    // nothing set or done
				tabularasa() ;

    		// set the image height and width variables to incoming now
			// Inset initially matches whole Bitmap.
				   ws = dibwid ;
				   hs = dibhyt ;
				  xsa = 0 ; xsb = ws ;
				  ysa = 0 ; ysb = hs ;

		    // set the sub-image to match the whole image, which
			// should be loaded by now.

				pBudResults->SubImageX = 0 ;
				pBudResults->SubImageY = 0 ;
				pBudResults->SubImageW = dibwid ;
				pBudResults->SubImageH = dibhyt ;

	        // get the incoming image file-name into the results struct.,
	        // and copy to szImgFile. 
                strcpy(pBudResults->BudImageFile, 
		               strcpy(szImgFile, szFile)) ;

	         // Analyse file name into components. If the incoming
		     // image file has a format known to the Bud Workshop,
			 // but has a non-standard name, it will be displayed,
			 // and can be processed, but no record of it will be
			 // kept in the Archive.

				if
				(
					ParseBudID(strcpy(f, szImgFile), Bud_ID) == IMG
				)
				{
					static LPSUITE sui ;
					static BUDID Bud ;
					char * p, * d ;
					char szImgName[100] ;
					char      pfx[ 50] ;
					char      pth[256] ;
					char instdate[100] ;
					static j, n, u, Ok ;

			        static UINT FID, ID, TYP ;
				    static HTREEITEM hti, hT, HT ;

								 Bud = * Bud_ID ;
				    StandardBudImage = 1 ;	// is standard image
					       toArchive = 1 ;	// so we will get results of some kind
						      newpfx = 0 ;	// presume known to the archive
							newsuite = 0 ;	// presume not suiteless

				// JulEpCpy[] is in Bud32.h, for SaveIniFile() ;
					strcpy(JulEpCpy, Bud.szJulEp) ;
				// isolate filename.ext
					strcpy(szImgName, DropPath(szImgFile)) ;

		// We are opening (actually, already have opened),
		// an _extant_ image, so we must have
		//				-  a prefix,
		//				-  an epoch,
		//				-  and a path

//****************** do we have the Prefix ID on record?

						strcpy(pfx, Bud.Prefix) ;	// the prefix string, more conveniently

					for (j = Ok = 0, n = A.iPfxIDs ; j < n ; j++)
					{
						if (!strcmp(pfx, A.szKnownpfx[j]))
						{
							I.pfxID = j ; Ok = 1 ; newpfx = 0 ; break ;	// we have the PFX ID on record
						}
					}
					if (!Ok) // we don't have the PFX ID on record
					{
						// arriving this way (i.e., opened for work),
						// without a known Prefix (because not found
						// in the search), this must be the
						// first ever encounter with this bud.
						//
						// get the new PFX ID on record now
						p = (char *)GlobalAlloc(GPTR,(strlen(pfx) + 2) * sizeof(char)) ;
						strcpy(p, pfx) ;
						I.pfxID = A.iPfxIDs ;	// use latest index
						A.szKnownpfx[I.pfxID] = p ;
						A.iPfxIDs++ ;			// bump up in anticipation of next
						// we now have a recorded prefix,
						// if it is not in the tree, get it in.
						if ((SearchTree(hWndTreeExp, 0, pfx, &ID, &TYP)) == (HTREEITEM)NULL)
						{
						FID = PutItmDat((UINT)I.pfxID, PFX) ;
						T.hTreeExpPfx[I.pfxID] = PutInTree(hWndTreeExp, 
										 TVI_ROOT,		// place in Tree View ROOT
										 TVI_ROOT,		// place in Tree View ROOT
										 pfx,			// the Prefix string
										 tvPfx,			// use Prefix icon
										 FID) ;			// store type and PFX ID in item data area
						}
						// create a default folder set and suite for the new prefix
						I.pS = CreateSuite(pfx, I.pfxID) ;
						newpfx = newsuite = 1 ;
						} // if (!Ok)


// ******************** do we have the current IMG PTH on record?

					// get path directly, in case ParseBudID() didn't.
					strcpy(pth, FetchPath(szImgFile)) ;
					for (j = Ok = 0, n = A.iGpthIDs ; j < n ; j++) //search the known path IDs
					{
						if (!strcmp(pth, A.szKnownpth[j]))
						{
							I.imgpth = j ; Ok = 1 ;	break ;	// path is already known
						}
					}
					if (!Ok)	// the Current IMG PTH is not on record
					{
						// get PTH string and ID on record now.
						p = (char *)GlobalAlloc(GPTR, (strlen(pth) + 2) * sizeof(char)) ;
						I.imgpth = A.iGpthIDs ;
						A.szKnownpth[I.imgpth] = p ;
						incpth("ProcessDIB(): new img pth")  ; // A.iGpthIDs++ ;
					}// if (!Ok)

						// acquaint the PFX ID with the IMG PTH ID
						Is_A_known_to_B(I.imgpth, PTH, I.pfxID, PFX, IMG) ;
						// acquaint the IMG PTH ID with the PFX ID
						Is_A_known_to_B(I.pfxID, PFX, I.imgpth, PTH, IMG) ;

//****************** do we have the IMG on record?

					for (j = Ok = 0, n = A.iImgIDs ; j < n ; j++)
					{
						if (!strcmp(szImgName, A.szKnownimg[j]))	// search the known IMGs
						{
							I.imgID = j ; Ok = 1 ;	// we have a record of the image.
							break ;
						}
					}
					if (!Ok) // the image is not on record.
					{
						      int sorted ;

						// get the IMG string and IMG ID on record now
						I.imgID = A.iImgIDs ;
						p = (char *)GlobalAlloc(GPTR, (strlen(szImgName) + 2) * sizeof(char)) ;
						strcpy(p, szImgName) ;
						A.szKnownimg[I.imgID] = p ;
						A.iImgIDs++ ;

						A.fKnownimgEp[I.imgID] = ep = Bud.JulEp ; // record the IMG epoch (julian)
							civildate() ;						// obtain the civil date and time
							calendar() ;
							sprintf(instdate, "%s  %s", dayt, Bud.szTime) ;
							d = (char *)GlobalAlloc(GPTR, (strlen(instdate) + 2) * sizeof(char)) ;
							strcpy(d, instdate) ;
							A.szImgdate[I.imgID] = d ;
							A.iInstYear[I.imgID] = Bud.BudYr ;
						   A.iInstMonth[I.imgID] = Bud.BudMon ;
						     A.iInstDay[I.imgID] = Bud.BudDay ;
						    A.iInstHour[I.imgID] = Bud.BudHr ;
						  A.iInstMinute[I.imgID] = Bud.BudMn ;
						  A.iInstSecond[I.imgID] = Bud.BudSc ;

						  A.iImgPfxID[I.imgID] = I.pfxID ; // the prefix ID matching the image ID

						  u = A.iNumImgperpfx[I.pfxID] ; // the latest number of images for this prefix ID

						// sort instance epochs and IDs into ascending instance epoch order
						sorted = 0 ;
						while (!sorted)
						{
						sorted = 1 ;
							for (j = 0 ; j < (A.iNumImgperpfx[I.pfxID] - 1) ; j++)
							{
							double T ;
							int iID ;
							if (A.fEpperpfx[I.pfxID][j] > A.fEpperpfx[I.pfxID][j + 1])
							{
												         T = A.fEpperpfx[I.pfxID][j] ;
							   A.fEpperpfx[I.pfxID][j]     = A.fEpperpfx[I.pfxID][j + 1] ;
							   A.fEpperpfx[I.pfxID][j + 1] = T  ;

												       iID = A.Imgperpfx[I.pfxID][j] ;
							   A.Imgperpfx[I.pfxID][j]     = A.Imgperpfx[I.pfxID][j + 1] ;
							   A.Imgperpfx[I.pfxID][j + 1] = iID ;
							 sorted = 0 ;
							}
							}
						}
						// get the earliest and latest epochs of the sequence
							A.fEarlyEp[I.pfxID] = A.fEpperpfx[I.pfxID][0] ;  
							A.fLaterEp[I.pfxID] = A.fEpperpfx[I.pfxID][u] ;

					// This is a new image, get it into the tree
					if ((HT = SearchTree(hWndTreeExp, 0, A.szKnownpfx[I.pfxID], &ID, &TYP)) != (HTREEITEM)NULL)
					{
					 FID = PutItmDat((UINT)I.imgID, IMG) ;
					 T.hTreeExpImg[I.imgID] = hT = PutInTree(hWndTreeExp,
							   HT,						// the prefix entry
							   HT,						// under the prefix entry
							   A.szKnownimg[I.imgID],	// the IMG string
						       tvImg,					// use IMG icon
							   FID) ;					// store type and IMG path ID in item data area

					 FID = PutItmDat((UINT)I.imgpth, IMGPTH) ;
					 T.hTreeExpImgPth[I.imgpth] = PutInTree(hWndTreeExp,
							   hT,						// the instance/image entry
							   hT,						// under the instance/image entry
							   A.szKnownpth[I.imgpth],	// the path string
						       tvImgpth,				// use IMG path icon
							   FID) ;					// store type and IMG path ID in item data area
					}
					}
					// we now have an image on record, old or new

						// acquaint the PFX ID with the IMG ID
						Is_A_known_to_B(I.imgID, IMG, I.pfxID, PFX, IMG) ;
						// acquaint the IMG ID with the PTH ID
						Is_A_known_to_B(I.imgpth, PTH, I.imgID, IMG, IMG) ;
						// acquaint the PTH ID with the IMG ID
						Is_A_known_to_B(I.imgID, IMG, I.imgpth, PTH, IMG) ;

							// this is the point at which a Suite needs
							// to be created and/or identified for a
							// known (registered) but suiteless image,
							// (as opposed to an in-session "arriviste").

							// how?

							// well, if the image is suiteless,
							// A.iNumsuiperpfx[I.pfxID] will be zero, surely.
							// so we create a set of folders in the current
							// archive

							if (A.iNumsuiperpfx[I.pfxID] == 0)
							{
								I.pS = CreateSuite(pfx, I.pfxID) ;
								// index is one less
								LastSuite  = UseSuite ;
								UseSuite = A.iNumsuiperpfx[I.pfxID] - 1 ;
								newsuite = 1 ;
							}
							


		// at this point, the image has loaded,
		// the archive is aware of it, and we
		// want to use its prefix

					  IsInst = 1 ;			// flag that we want an instance with
					BudPfxID = I.pfxID ;	// the incoming PFX, not a series

		// next, we want to use or select a suite

		// if NOT selecting the suite from the tree, use the Pick-a-Suite dialog
				if (!LoadImgbyTree)
				{
					// is it the first sight of any instance of it in the current session?
					if (!openpfx[BudPfxID])	// if was not the first sight
					{
						if (!newpfx)			// if it is NOT an instance of a new prefix,
						{
						  DialogBox(hInst,						// go pick a suite
									MAKEINTRESOURCE(IDD_LOAD),
									hWndCtrl,
									PickSuiteDlgProc
									) ;
						}
					// one or more instances of this prefix
					// have been opened in this session
						openpfx[BudPfxID]++ ;
					}
				} // if (!LoadImgbyTree)

		// use the currently-selected suite of paths

					sui = A.pSuiteperpfx[BudPfxID][UseSuite] ;

					// Cancel after every use, to allow sequencer to do its work,
					// or the processing of an arriviste.
					// ---should not be needed now---
					//if (LoadImgbyTree) LoadImgbyTree = 0 ;
				 
		//********************************
		// Check out INI file's record
		//********************************

	          // get the incoming ini file-name into the results struct.,
	          // and copy to szIniFile for SaveIniFile() later. 
	             strcpy(pBudResults->BudTextFile,
		             strcpy(szIniFile, AddExt(DropPath(szFile),".ini"))) ;

//*************** do we have this INI file on record?
				 for ( j = Ok = 0, n = A.iIniIDs ; j < n ; j++)
				 {
					 if (!strcmp(szIniFile, A.szKnownini[j]))
					 {
						 I.iniID = j ; Ok = 1 ; // this INI is on record
						 break ;
					 }
				 }
				 if (!Ok) // this particular INI is not on record anywhere
				 {
				// get the INI string and ID on record now
					I.iniID = A.iIniIDs ;
					p = (char *)GlobalAlloc(GPTR,(strlen(szIniFile) + 2) * sizeof(char)) ;
					strcpy(p, szIniFile) ;
					A.szKnownini[I.iniID] = p ;
					A.iIniIDs++ ;
					// acquaint the PFX ID with this INI ID
					Is_A_known_to_B(I.iniID, INI, I.pfxID, PFX, INI) ;
					// acquaint the IMG ID with this INI ID
					Is_A_known_to_B(I.iniID, INI, I.imgID, IMG, INI) ;
				 }

				 // if both the PFX and the INI are new, or
				 // if the corresponding image is Suiteless
				 // the Suite will just have been created,
				 // and will be used now.
				 //		otherwise, the Suite created
				 // by InspectFile() will be used.

				    I.inipth = sui->iINIpth ;					// get the INI path ID from the Suite						
					strcpy(szIniPath, A.szKnownpth[I.inipth]) ;	// form the INI file name
					strcat(szIniPath, "\\" ) ;
					strcat(szIniPath, szIniFile) ;			    // form the fully qualified open/save path

				// if the INI actually exists, use its contents 
				// to show the latest state of the instance.
				//		if it does not yet exist, it will be
				// created on SaveIniFile(), and then contain such
				// results as are obtained now - including none!
				// that is, records will exist even if empty.

		if ((hbud = OpenFile(szIniPath, &of, OF_EXIST)) != HFILE_ERROR)
 		{
			// the INI exists.

			// see if it has the old DAT info along

			hasDATinfo = 0 ; // assume it hasn't

			gpps("WASDAT","BudTextFile", "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None"))
				if (!strcmp(buff, szIniFile)) hasDATinfo = 1 ;	// it has it.

		   // Check image dimensions stored in the INI
		   // against those of the incoming image.

		   // Presume no change.
		      ImgDimsDiffer = 0 ;

		   // Try for recorded width
			gpps( "Dimensions", "Pixel Width", "None",
				   buff, (DWORD)255, szIniPath ) ;
			
			if (strcmp( buff,"None") != 0)	 // if we altogether have an entry..
			{
				  recordedwid = atoi(buff) ; // get the recorded width.
				if (dibwid != recordedwid) // if it is different from the incoming
				ImgDimsDiffer = 1 ;          // flag the difference up.
			}

			// try for recorded height.
			gpps( "Dimensions", "Pixel Height", "None",
				   buff, (DWORD)255, szIniPath) ;
		  
			if (strcmp( buff,"None") != 0)	 // if there is an entry at all...
			{
				  recordedhyt = (UINT32)atoi(buff) ; // get the recorded height.
				if (dibhyt != recordedhyt) // if different from incoming
				ImgDimsDiffer = 1 ;          // flag difference up.
			}

			// if the recorded dimensions differ from the incoming..

			if (ImgDimsDiffer)	// beep and report.
			{
					MessageBeep(MB_ICONEXCLAMATION) ;

			 sprintf(mismatch,
                     "The dimensions of this image\n" \
                     "no longer match those recorded\n" \
                     "in the Archive.\n\n\n" \
                     "These details remain in the Archive, and are taken to be\n" \
                     "valid for other Archive operations.\n\n" \
                     "As the image has changed,the original\n" \
                     "match cannot be recovered automatically.\n\n" \
                     "You are strongly advised to re-process\n" \
                     "this instance to re-establish a match of image\n" \
                     "to Archive.\n\n") ;
			 
							  MessageBox(NULL,
										 mismatch,
										"WARNING: Image/Archive Mismatch",
										 MB_ICONEXCLAMATION|MB_OK) ;
			}

	  // Get the number of measurement-levels used now.
			
			gpps("Dimensions","Levels Used", "None",
				  buff, (DWORD)255, szIniPath) ;
			
			if (strcmp(buff,"None") != 0)
			{ Levels = atoi(buff) ; levels_exist = 1 ; } // there are levels and recorded measurements. Get ready for them.
			else
			{ Levels = dfault ; levels_exist = 0 ; }	//  there are no levels or recorded measurements.  Set to the defaults.

			{
				 int L ;
				char b[10] ;
		
	  // Next, check out the origins of the measurements.
	  // If no origin-data is recorded, then
	  // assume the measurements were manually
	  // obtained.  This will preserve them. If a track file is
	  // later found, give option to use it.


				// presume that origin data is available
				for (L = 1, NoOrgData = 0 ; L <= Levels ; L++)
				{
					sprintf(b, "%d", L) ;
					gpps("Dimensions", b, "None",
						  buff, (DWORD)255, szIniPath) ;

					if (strcmp(buff,"None") != 0) // is available
					{
						LEdgeOrg[L] = atoi(ParseLine(buff,0)) ;
						REdgeOrg[L] = atoi(ParseLine(buff,1)) ;
					}
					else // isn't available
					{
						// Flag that no origin data is available.
						NoOrgData = 1 ;
						// but, to preserve measurements, assume manual origin.
						// If a track file is found below, allow review then.
						LEdgeOrg[L] = REdgeOrg[L] = EYEBALLED ;
					}
				}

			// get the level inclusions
			for (L = 1 ; L <= Levels ; L++)
			{
					sprintf(b, "%d", L) ;
					gpps("Inclusions", b, "None",
						buff, (DWORD)255, szIniPath) ;

						if (strcmp(buff,"None") != 0) // is available
						{
						IncludeLev[L] = atoi(buff) ;
						}
			}
				
			} // No levels on record.


	// get the measurement mode (growth, or linear).
	// if no mode recorded, then assume linear.
			gpps( "Dimensions", "Mode", "None", buff, (DWORD)255, szIniPath ) ;

		GrowthMeasure = (strcmp(buff, "None") && !strcmp(buff, "Growth")) ? 1 : 0 ;

	// see if we have the line-scan colour on record.
	// if we don't, assume 'all' (i.e. grayscale).
			gpps( "Dimensions", "ScanColour", "None", buff, (DWORD)255, szIniPath ) ;
			if (strcmp(buff, "None"))
			{
				if (!strcmp(buff, "A"))	scancolour = 0 ;	// all (grayscale)
				if (!strcmp(buff, "R"))	scancolour = 1 ;	// on red
				if (!strcmp(buff, "G"))	scancolour = 2 ;	// on green
				if (!strcmp(buff, "B"))	scancolour = 3 ;	// on blue
			} else scancolour = 0 ;							// no record, use 'all'.

	// get the calibration status.
			gpps( "Dimensions", "Calibration", "None", buff, (DWORD)255, szIniPath ) ;
			if (strcmp(buff,"None") || strcmp(buff," 0"))
			{
				static x1, y1, x2, y2 ;
				x1 = y1 = x2 = y2 = 0 ;
			calibrated = CAL1SET = CAL2SET = 1 ;
			// Pick up recorded calibration-mark positions.
			// These have been recorded (when set) since Feb. 2001.
			gpps( "Dimensions", "xCal_1", "None", buff, (DWORD)255, szIniPath ) ;
			if (strcmp(buff,"None") && strcmp(buff," 0"))
			{xBCal1 = atoi(buff) ; x1 = 1 ;}

			gpps( "Dimensions", "yCal_1", "None", buff, (DWORD)255, szIniPath ) ;
			if (strcmp(buff,"None") && strcmp(buff," 0"))
			{yBCal1 = atoi(buff) ; y1 = 1 ;}
			if (x1 && y1){ CAL_1_AVAILABLE = 1 ; UpdateWindow(hWndBud) ; }	// show 1st Mark position
			else xBCal1 = yBCal1 = 0 ;			// 1st Mark position was not recorded

			gpps( "Dimensions",	"xCal_2", "None", buff, (DWORD)255, szIniPath ) ;
			if (strcmp(buff,"None") && strcmp(buff," 0"))
			{xBCal2 = atoi(buff) ; x2 = 1 ;}

			gpps( "Dimensions", "yCal_2", "None", buff, (DWORD)255, szIniPath ) ;
			if (strcmp(buff,"None") && strcmp(buff," 0"))
			{yBCal2 = atoi(buff) ; y2 = 1 ;}
			if (x2 && y2){ CAL_2_AVAILABLE = 1 ; UpdateWindow(hWndBud) ; }	// show 2nd Mark position.
			else xBCal2 = yBCal2 = 0 ;										// 2nd Mark position was not recorded.
			
			gpps( "Dimensions",	"Units", "None", buff, (DWORD)255, szIniPath ) ;
			if (!strcmp(buff,"Inches")) 
			{ Units = IMPERIAL ; PlayList[clips++] = 6 ; }
			else
			if (!strcmp(buff,"Millimetres"))
			{ Units = METRIC ;   PlayList[clips++] = 7 ; }
			else ResetCalibration() ;	// should never get here

			gpps( "Dimensions", "Inter-Mark size", "None", buff, (DWORD)255, szIniPath ) ;
			if (strcmp(buff,"None")) CalSize = atof(buff) ;
			else ResetCalibration() ;
			 
			gpps( "Dimensions",	"Inter-Mark DIBits", "None", buff, (DWORD)255, szIniPath ) ;
			if (strcmp(buff,"None"))
			{
			 InterCalMarkDIBits = atof(buff) ;
			  switch (Units)
			  {
			   case IMPERIAL: DIBitsPerIn = InterCalMarkDIBits / CalSize ; break ;
			   case METRIC:   DIBitsPerMm = InterCalMarkDIBits / CalSize ; break ;
			  }
			}
			else
			{
				DIBitsPerIn = DIBitsPerMm = 0.0 ;
				ResetCalibration() ;
			}
		 }
		 if (!calibrated)
		 {
			ResetCalibration() ;
			PlayList[clips++] = 8 ;
		 }

		 if (hasDATinfo)
		 {
			 char szDimWarn[] = {"Warning: The Inset for the incoming image\ndoes not fit in the image."} ;  
			// OK, read in all the data that was formerly in the DAT and is now in the INI

			gpps("WASDAT", "BudSpec",      "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudSpecTxt, buff) ;
			gpps("WASDAT", "BudPlace",     "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudPlaceTxt, buff) ;
			gpps("WASDAT", "BudLatitude",  "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudLatitudeTxt, buff) ;
			gpps("WASDAT", "BudLongitude", "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudLongitudeTxt, buff) ;
			gpps("WASDAT", "BudImageFile", "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudImageFile, buff) ;
			gpps("WASDAT", "BudDataFile",  "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudDataFile, buff) ;
			gpps("WASDAT", "BudTextFile",  "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudTextFile, buff) ;
			gpps("WASDAT", "BudDateTxt",   "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudDateTxt, buff) ;
			gpps("WASDAT", "BudTimeTxt",   "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) strcpy(pBudResults->BudTimeTxt, buff) ;

			gpps("WASDAT", "NumHyts",   "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->NumHyts = atoi(buff) ;

			gpps("WASDAT", "SubImageX", "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->SubImageX = atoi(buff) ;

			gpps("WASDAT", "SubImageY", "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->SubImageY = atoi(buff) ;

			gpps("WASDAT", "SubImageW", "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->SubImageW = atoi(buff) ;

			gpps("WASDAT", "SubImageH", "None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->SubImageH = atoi(buff) ;   // <-- Bad Bug! This line was missing. 27/09/2011

			if((pBudResults->SubImageH + pBudResults->SubImageY) > dibhyt
				||
			   (pBudResults->SubImageW + pBudResults->SubImageX) > dibwid)
				MessageBox(NULL, szDimWarn, "Inset Dimensions", MB_OK) ;

				for (i = 1 ; i <= Levels ; i++)
				{
					strcpy(more, "Edges") ; strcat(more, _itoa(i, num, 10)) ;
					gpps("WASDAT", more, "None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pBudResults->Edges[i] = atoi(buff) ;
				}

		  gpps("WASDAT", "BudMag","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->BudMag = atof(buff) ;
		  gpps("WASDAT", "BudLength","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->BudLength = atof(buff) ;
		  gpps("WASDAT", "BudTilt","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->BudTilt = atof(buff) ;

		  gpps("WASDAT", "BudTopPoleX","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->BudTopPoleX = atof(buff) ;
		  gpps("WASDAT", "BudTopPoleY","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->BudTopPoleY = atof(buff) ;
		  gpps("WASDAT", "BudBotPoleX","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->BudBotPoleX = atof(buff) ;
		  gpps("WASDAT", "BudBotPoleY","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->BudBotPoleY = atof(buff) ;

		  gpps("WASDAT", "LeftProjLambda","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->LeftProjLambda = atof(buff) ;
		  gpps("WASDAT", "LeftProjMRD","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->LeftProjMRD = atof(buff) ;
		  gpps("WASDAT", "LeftRegrLambda","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->LeftRegrLambda = atof(buff) ;
		  gpps("WASDAT", "LeftRegrMRD","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->LeftRegrMRD = atof(buff) ;

		  gpps("WASDAT", "RightProjLambda","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->RightProjLambda = atof(buff) ;
		  gpps("WASDAT", "RightProjMRD","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->RightProjMRD = atof(buff) ;
		  gpps("WASDAT", "RightRegrLambda","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->RightRegrLambda = atof(buff) ;
		  gpps("WASDAT", "RightRegrMRD","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->RightRegrMRD = atof(buff) ;

		  gpps("WASDAT", "DiamProjLambda","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->DiamProjLambda = atof(buff) ;
		  gpps("WASDAT", "DiamProjMRD","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->DiamProjMRD = atof(buff) ;
		  gpps("WASDAT", "DiamRegrLambda","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->DiamRegrLambda = atof(buff) ;
		  gpps("WASDAT", "DiamRegrMRD","None", buff, (DWORD)255, szIniPath) ;
			if (strcmp(buff, "None")) pBudResults->DiamRegrMRD = atof(buff) ;

		  for (k = 1 ; k <= Levels ; k++)
		  {
					_itoa(k, num, 10) ;
				strcpy(more, "RProjDev") ; strcat(more, num) ;
				gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->RProjDev[k] = atof(buff) ;

				strcpy(more, "LProjDev") ; strcat(more, num) ;
				gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->LProjDev[k] = atof(buff) ;

				strcpy(more, "BProjDev") ; strcat(more, num) ;
				gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->BProjDev[k] = atof(buff) ;

				strcpy(more, "RRegrDev") ; strcat(more, num) ;
				gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->RRegrDev[k] = atof(buff) ;

				strcpy(more, "LRegrDev") ; strcat(more, num) ;
				gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->LRegrDev[k] = atof(buff) ;

				strcpy(more, "BRegrDev") ; strcat(more, num) ;
				gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->BRegrDev[k] = atof(buff) ;
		  }

				gpps("WASDAT", "RProjBestAt","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->RProjBestAt = atoi(buff) ;
				gpps("WASDAT", "LProjBestAt","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->LProjBestAt = atoi(buff) ;
				gpps("WASDAT", "BProjBestAt","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->BProjBestAt = atoi(buff) ;

				gpps("WASDAT", "RRegrBestAt","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->RRegrBestAt = atoi(buff) ;
				gpps("WASDAT", "LRegrBestAt","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->LRegrBestAt = atoi(buff) ;
				gpps("WASDAT", "BRegrBestAt","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->BRegrBestAt = atoi(buff) ;

				gpps("WASDAT", "RightRegrCoeff","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->RightRegrCoeff = atof(buff) ;
				gpps("WASDAT", "LeftRegrCoeff","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->LeftRegrCoeff = atof(buff) ;
				gpps("WASDAT", "BothRegrCoeff","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pBudResults->BothRegrCoeff = atof(buff) ;

//****************  Measure stuff started here in the DAT

				gpps("WASDAT","xTopPole","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pMeasure->iTopPole.x = atof(buff) ;

				gpps("WASDAT","yTopPole","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pMeasure->iTopPole.y = atof(buff) ;

				gpps("WASDAT","xBotPole","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pMeasure->iBotPole.x = atof(buff) ;

				gpps("WASDAT","yBotPole","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pMeasure->iBotPole.y = atof(buff) ;

				gpps("WASDAT","AxisGrad","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pMeasure->iAxisGradIcept.x = atof(buff) ;

				gpps("WASDAT","AxisIcept","None", buff, (DWORD)255, szIniPath) ;
				if (strcmp(buff, "None")) pMeasure->iAxisGradIcept.y = atof(buff) ;

							for (k = 1 ; k <= Levels ; k++)
				{
								_itoa(k, num, 10) ;
					strcpy(more, "xAxisCut") ;	  strcat(more, num) ; 
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iAxisCuts[k].x = atof(buff) ;

					strcpy(more, "yAxisCut") ;	  strcat(more, num) ; 
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iAxisCuts[k].y = atof(buff) ;
				}

							for (k = 1 ; k <= Levels ; k++)
				{
							_itoa(k, num, 10) ;
					strcpy(more, "LevelGrad") ;	  strcat(more, num) ;
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iLevGradIcepts[k].x = atof(buff) ;

					strcpy(more, "LevelIcept") ;	  strcat(more, num) ; 
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iLevGradIcepts[k].y = atof(buff) ;
				}

 							for (k = 1 ; k <= Levels ; k++)
				{
							_itoa(k, num, 10) ;
					strcpy(more, "xLeft") ;	  strcat(more, num) ;
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iLeftCut[k].x = atof(buff) ;
					
					strcpy(more, "yLeft") ;	  strcat(more, num) ;
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iLeftCut[k].y = atof(buff) ;
				}
				
							for (k = 1 ; k <= Levels ; k++)
				{
							_itoa(k, num, 10) ;
					strcpy(more, "xRight") ;	  strcat(more, num) ;
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iRightCut[k].x = atof(buff) ;

			        strcpy(more, "yRight") ;	strcat(more, num) ;
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iRightCut[k].y = atof(buff) ;
				}

						for (k = 1 ; k <= Levels ; k++)
				{
						_itoa(k, num, 10) ;
					strcpy(more, "LeftRadius") ;	strcat(more, num) ;
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iLeftRad[k] = atof(buff) ;

					strcpy(more, "RightRadius") ;	strcat(more, num) ;
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iRightRad[k] = atof(buff) ;

					strcpy(more, "Diameter") ;	strcat(more, num) ;
					gpps("WASDAT", more,"None", buff, (DWORD)255, szIniPath) ;
					if (strcmp(buff, "None")) pMeasure->iDiameter[k] = atof(buff) ;
				 }
						goto skipDAT;  // we don't need the DAT
		}



		} // No INI
		// If we fall through to here, there's no .INI yet
		// for this date, but it will be created on Save.

		//********************************
		// Check out DAT file's record
		//********************************

	          // get the Dat file-name into the results struct.,
	          // and copy to szDatFile for SaveDatFile() later.

	             strcpy(pBudResults->BudDataFile,
					 strcpy(szDatFile, AddExt(DropPath(szFile),".dat"))) ;

//*************** do we have this DAT file on record?
				 if (useDATs)
				 {
				 for (j = Ok = 0, n = A.iDatIDs ; j < n ; j++)
				 {
					 if (!strcmp(szDatFile, A.szKnowndat[j]))
					 {
						 I.datID = j ; Ok = 1 ; break ; // this DAT is on record
					 }
				 }
				 if (!Ok) // this DAT is not on record
				 {
				// get the DAT string and ID on record now
					I.datID = A.iDatIDs ;
					p = (char *)GlobalAlloc(GPTR, (strlen(szDatFile) + 2) * sizeof(char)) ;
					strcpy(p, szDatFile) ;
					A.szKnowndat[I.datID] = p ;
					A.iDatIDs++ ;
				 }
					// acquaint the PFX ID with this DAT ID
					Is_A_known_to_B(I.datID, DAT, I.pfxID, PFX, DAT) ;
					// acquaint the IMG ID with this DAT ID
					Is_A_known_to_B(I.datID, DAT, I.imgID, IMG, DAT) ;

				 // if the PFX is new, or if the DAT's
				 // corresponding image is Suiteless
				 // the Suite will just have been created,
				 // and will be used now.

				 // otherwise, the Suite created
				 // by InspectFile() will be used.

				 I.datpth = sui->iDATpth ;
				 strcpy(szDatPath, A.szKnownpth[I.datpth]) ;
				 strcat(szDatPath, szDatFile) ;
				 }

// *******************************
// Check for DAT file's actual existence
// *******************************

				// if the DAT does not yet exist, it will be created
				// immediately, and then contain such results as are
				// obtained now - including none! that is, nil results
				// will record as empty records.

				 // 30/09/2011
				 // There is an attempt to eliminate the DAT files, after
				 // incorporating their data into the corresponding INI
				 // files. The existing DATs are being "sequestered",
				 // rather than deleted, in case things go awry.

				 if (hasDATinfo)  // but if we already have the DAT info from the INI ---
				 {
					 haveOldDAT = 0 ; // 1st assume old DAT file is gone and was not oldstyle
						// but check it out --
					 if ((hdat = _findfirst(szDatPath, &finfo)) != -1L ) // if we still have the DAT --
					 {
					 haveOldDAT = 1 ; // we still have the old DAT file
					 if (finfo.size < 8768) // is it oldstyle?
						 convertDAT() ;		// convert to new style before sequestering it
					 }
					 goto skipDAT ;
				 }
	
	// we don't have the DAT info in the INI
	// use and convert the DAT itself, if there is one.

				 // This should phase itself out as existing DAT info
				 // becomes embedded in the INIs

 if ((hdat = _findfirst(szDatPath, &finfo)) != -1L )
  {
       // there's a .DAT file, so read it in now. This will reset the
	   // states of the images, settings and measurements to those
	   // obtained during the most recent session with this instance.

		  if (finfo.size < 8768) // is old-style .DAT file. Convert.
			  convertDAT() ;
		  else
			  ReadDatFile(0) ;  // is in new format. just read it in as is.

skipDAT:	  InterpretData(0) ;

		 // Good moment to set up the trial PC parms to the
		 // those of the incoming bud, if they exist,
		 // else set to defaults.

   if ((TrialLam = pBudResults->DiamProjLambda) == 0.0)
			    TrialLam = 2.0 ;
		   if ((TrialRad = 0.5 * pMeasure->iDiameter[(Levels+1)/2]) == 0.0)
			    TrialRad = 0.25 ;

		// Also, recreate the mid points, and find the axial displacement radii 

	  for ( i = 1 ; i <= Levels ; i++ )
	  {
		   MidPt[i].x = ( pMeasure->iLeftCut[i].x +
			              pMeasure->iRightCut[i].x ) / 2.0 ;
		   MidPt[i].y =	( pMeasure->iLeftCut[i].y +
			              pMeasure->iRightCut[i].y ) / 2.0 ;
		AxisRadius[i] = sqrt(pow(pMeasure->iAxisCuts[i].x - MidPt[i].x, 2.0) +
						     pow(pMeasure->iAxisCuts[i].y - MidPt[i].y, 2.0));
	  
	  // If a mid point is to the left of the interpole axis,
	  // make the corresponding axis radius negative ;

		if (MidPt[i].x < pMeasure->iAxisCuts[i].x) AxisRadius[i] *= -1.0 ;
	  }

	  AxisRadius[0] = 0.0 ;

      }
      else        
        {
	   // no, it's not there, so ..
	   // ..create an empty .DAT file, and close it.

		  // er, let's not!
		  // We are trying to do away with DATs

	      //hdat = OpenFile(szDatPath,&of,OF_CREATE) ;
	      //_lclose(hdat) ;

		  ; // dummy op
        }

		      toArchive = 1 ;
			  
	//*******************************
	// Check for TRK file's existence
	//*******************************

	    // Does a .TRK file exist for this bud instance?

			  // PROBLEM here!
			  // If there is a track file, then the suite should know about it by now.
			  // If it does not, then there is no track, at least for the currently
			  // selected suite.
			  if (sui->iTRKpth > -1)	// Work around, but code not good here.  FIX IT!!
			  {
				 I.trkpth = sui->iTRKpth ;
				 strcpy(szTrkPath, A.szKnownpth[I.trkpth]) ;
		         strcpy(szTrkFile, AddExt(DropPath(szFile),".trk")) ;
				 strcat(szTrkPath, szTrkFile) ;

		  if ((bfile = _findfirst(szTrkPath, &finfo)) != -1L) // go find it
		  {
		     static int earlier, i, j ;
		 // Ok we've found it...
		 // What size is the file ? (Delete it if zero)

			 if ((filesize = finfo.size) == 0L) 
			   { msgbox = 1 ;
				 MessageBox(NULL,
				           "Track File is Empty. Deleting..","Size Error", MB_OK) ;
				 msgbox = 0 ;
			                goto Zap_it ;
			   }

		  eptmp = ep ; // store current ep

		 // Define the "critical date" (1st Feb, 2001) as a julian epoch.
		    day = 1	;
			 mo = 2 ;
			 yr = 2001 ;
		 setepoch() ;
		 epcrit = ep ;

		 // When was this file last written?

			  sprintf(sbuff, "%s", ctime(&(finfo.time_write))) ;
			  // parse for the day
			  for ( i = 8, j = 0 ; i <= 9 ; fday[j++] = sbuff[i++] ) ;
			  fday[2] = '\0' ; day = atoi(fday) ;
			  // the month
			  for ( i = 4, j = 0 ; i <= 6 ; fmon[j++] = sbuff[i++] ) ;
			  fmon[3] = '\0' ;
			       mo = 0 ; while (strcmp( mon[mo++], fmon)) ;
			  // the year
			  for ( i = 20, j = 0 ; j <= 23 ; fyr[j++] = sbuff[i++] ) ;
			  fyr[4] = '\0' ; yr = atoi(fyr) ;
			  setepoch() ;
			  epwritten = ep ;

		  // When was this track-file first made?
		  // (We take the instance date.
		  //  It is probably close enough.)

		    day = Bud_ID->BudDay ;
		     mo = Bud_ID->BudMon ;
		     yr = Bud_ID->BudYr ;

			 setepoch() ;

		     epdone = ep ;

			 ep = eptmp ; // restore current ep

	        earlier = 0 ;
		if (epdone < epcrit && epwritten < epcrit)
			earlier = 1 ;

		if (earlier)
		{
			char str[100] ;
			sprintf(str,
                "********   Please Note..  ********\n\n" \
                "This Track File predates Feb. 2001.\n\n\n" \
                "It will be deleted.  However, the\n" \
                "measurements and results obtained\n" \
                "from it will be retained until its bud\n" \
                "instance is re-tracked or re-measured.") ;
			msgbox = 1 ;
			MessageBox(NULL, str, "Obsolete Track File.",
				       MB_ICONEXCLAMATION|MB_OK) ;
			msgbox = 0 ;

Zap_it:			       if (htrack != (HFILE)NULL) _lclose(htrack) ;
			           htrack = OpenFile(szTrkPath, &of, OF_DELETE) ;
					   htrack = (HFILE)NULL ; // rub it in.
					autotrack = 0 ;
				  autotracked = 0 ;
				  autolftdone = 0 ;
				  autorytdone = 0 ;
				    showTrack = 0 ;
					if (T.hTreeExpTrk[I.trkID] != NULL) // remove from the tree
						TreeView_DeleteItem(hWndTreeExp, T.hTreeExpTrk[I.trkID]) ;
					// need to update the archive generally here, surely

			           goto no_track ;
		}

		  // it exists & is OK. open it.  

   	    if ((htrack = OpenFile(szTrkPath, &of, OF_EXIST)) == HFILE_ERROR)
			{
				char str[255] ;
				sprintf(str,
                "Failed to Open Track File %s\n" \
                "Assuming it is not available.\n" \
                "Skipping.\n",
                 szTrkPath) ;
				msgbox = 1 ;
				MessageBox( NULL,str, "Open Track File", MB_OK) ;
				msgbox = 0 ;
				goto no_track ;
			}

			// get the tracking data: if a problem, report and skip
				if (!ReadTrkFile(&Tk, szTrkPath))
				{
					msgbox = 1 ;
					MessageBox(NULL, "No Track Data!", "Problem with ReadTrkFile()", MB_OK) ;
					msgbox = 0 ;
					autotrack = 0 ;
				  autotracked = 0 ;
				  autolftdone = 0 ;
				  autorytdone = 0 ;
				    showTrack = 0 ;
					/*++
					if (T.hTreeExpTrk[I.trkID] != NULL)
						TreeView_DeleteItem(hWndTreeExp, T.hTreeExpTrk[I.trkID]) ;
					--*/
					goto no_track ;
				}

		  // set the buttons and the program to reflect the tracking state
				 autotrack   = 1 ;
				 autotracked = 1 ;
				 autolftdone = 1 ;
				 autorytdone = 1 ;
				   showTrack = 1 ;

	   if (NoOrgData && TOPSET && BOTSET)
	   {
		   int UserSays ;
		   char msg[200] ;

           sprintf(msg,
           "As no Method-of-Measurement information is" \
           "\navailable,Manual Measurement has been assumed." \
           "\n\nHowever, a Track file exists," \
           "\nand measurements may be obtained" \
           "\nfrom its tracking data." \
           "\n\n(Please Note:\nExisting non-track measurements\nwill be lost.)" \
           "\n\nDo you wish to obtain measurements" \
           "\nfrom the tracking data now?" ) ;
		   msgbox = 1 ;
		   UserSays = MessageBox(NULL,
			    msg,
			   "No Origin Information.",
			    MB_ICONEXCLAMATION|MB_YESNO) ;
		   msgbox = 0 ;

		   switch (UserSays)
		   {
		   case IDYES: // We signal to move a pole, but do not move it,
			   SendMessage(hWndCtrl,WM_COMMAND, SET_LO_POLE, 0L) ;
		    // and accept the "new" pole position at once.
			// This invokes MeasureTrackedBud(), and updates origins.
			// Oh my, clever stuff, eh? ;-)
			   SendMessage(hWndCtrl,WM_COMMAND,ENTER_ACCEPT_POLE, 0L) ;
			   break ;
		   case IDNO:
		   default: break ;
		   }
	   }
no_track:;
		} 
		else	// there is no tracking file.
			{
				Note(1, "Track File Not Found.") ;
			}
		}//if (sui->iTRKpth > -1) there is no track set in the suite yet
				}
				else //This is not a Standard Bud Image
					StandardBudImage = 0 ;
// end if (ParseBudID())

		   if (gotimage) // if we already have an image, it is being replaced
				   strcpy(szArchFile, szFile) ;

			   gotimage++ ;	// confirm that we have a replacement image.

			   // we have an image: if it's standard,
			   // set the BL flag TRUE, else FALSE
			   BL = (StandardBudImage) ? TRUE : FALSE ;

	          //tell the dialog boxes and so on
	              RecordDimensions() ;
			      RecordLambdas() ;

			  // wipe the windows and then show 
			  // results according to current state flags
			   SendMessage(hWndBud, WM_COMMAND, IDM_SHOWBM, 0L) ;


			   SendMessage(hWndBud, WM_COMMAND, ACCEPT_TRACK,0L) ;

			   // Locate the drag rectangles at the poles
			   // if to show them...
					if (ShowDragHandles)
					{
				      SetDragHandles(0) ;
					  UpdateWindow(hWndBud) ;
					  DrawDragHandles(hWndBud) ;
					}

			   // If either pole unset, turn on blinking of set pole buttons
			   // This info comes from the instance .DAT file
					 if (!TOPSET || !BOTSET)
				     Blink = SetTimer(hWndBud, IDT_BTIMER, tBlink, NULL) ;

			   // If uncalibrated, turn on blinking of calibration buttons
			   // This info comes from the instance .INI file.
					 if (!CAL1SET || !CAL2SET)
					 Blink1 = SetTimer(hWndBud, IDT_BTIMER1, tBlink1, NULL) ;
		
               // Enable "Details" item on menu
					 EnableMenuItem(hmenu,1,MF_BYPOSITION|MF_ENABLED) ;
					 DrawMenuBar(hWndCtrl) ;
					 

	
			   // If not a valid bud image, say so.
				if (!StandardBudImage)
				{
					strcat(f, MsgTxt) ;
					msgbox = 1 ;
					MessageBox( NULL,
					            f,
					           "Please Note...",
							    MB_ICONEXCLAMATION|MB_OK
                              ) ;
					msgbox = 0 ;

				}

			  // If running commentary turned on, tell us
			  // what's what with the latest arrival.

				if (commentary)
					for ( i = 0 ; i < clips ; i++ )
				{
					PlaySound(sBite[PlayList[i]], NULL, SND_SYNC) ;
				}
} // ProcessDIB()

int ReadTrkFile(LPTRKINFO trk, char *TrkPath)
{
	   int this_hs ;
	 HFILE htrack ;
  OFSTRUCT of ;

    	 if ((htrack = OpenFile(TrkPath, &of, OF_READ)) != HFILE_ERROR)
		{
				// Get the incoming number of track heights.
				// This is just the height in pixels of the corresponding bitmap.
				_hread(htrack, (LPBYTE)&this_hs, sizeof(int)) ;
						trk->hyt = this_hs ;

				// Set up storage for autotrack.
				// Old storage is first de-allocated.
				 if (!FreeTrackMemory(trk))
				 {
					 MessageBox(NULL,
						 "FreeTrackMemory() returned zero",
						 "Problem: Free Track Memory",
						 MB_OK ) ;
									return 0 ;
				 }
		
		  // Right and left Hi and Lo indices are
		  // initialised, and the end-point (Ep)
		  // array-members are given a negative
		  // value to indicate "no capture".
			AllocTrackHyts(trk, this_hs) ;

		  // bring in the track limit indices
	        _hread(htrack, (LPBYTE)trk->Blftloidx,  sizeof(int)) ;
	        _hread(htrack, (LPBYTE)trk->Blfthiidx,  sizeof(int)) ;
	        _hread(htrack, (LPBYTE)trk->Brytloidx,  sizeof(int)) ;
	        _hread(htrack, (LPBYTE)trk->Brythiidx,  sizeof(int)) ;
			
		  // bring in the raw data for the left track
			_hread(htrack, (LPBYTE)trk->Beplft, this_hs * sizeof(int)) ;
		  // bring in the raw data for the right track
			_hread(htrack, (LPBYTE)trk->Bepryt, this_hs * sizeof(int)) ;
		  // close the tracking file
			_lclose(htrack) ;

		  // make up a linked list for the left side. Blcapt is the number of points in it.
			trk->Blcapt = LinkTrackPoints(trk, LEFT) ;
		  // make up a linked list for the right side. Brcapt is the number of points in it.
			trk->Brcapt = LinkTrackPoints(trk, RIGHT) ;

			return this_hs ;
		}
	return 0 ;
}

void ReadDatFile(int oldstyle)
{
         DWORD  dwBytesRead1 = 0;
         DWORD  dwBytesRead2 = 0;
  LPBUDRESULTS  B ;
 LPOBUDRESULTS OB ;
     LPMEASURE  M ;
    LPOMEASURE OM ;
	    HANDLE hbud ;

	  B = pBudResults ;
	  M = pMeasure ;
	 OB = pOBudResults ;
	 OM = pOMeasure ;

	 hbud = CreateFile(szDatPath,               // file to open
                       GENERIC_READ,          // open for reading
                       FILE_SHARE_READ,       // share for reading
                       NULL,                  // default security
                       OPEN_EXISTING,         // existing file only
                       FILE_ATTRIBUTE_NORMAL, // normal file
                       NULL);                 // no attr. template
 
    if (hbud == INVALID_HANDLE_VALUE) 
    { 
        MessageBox(NULL,"Can't open the DAT",NULL, MB_ICONEXCLAMATION|MB_OK);
    }
	  if (oldstyle)
	  {
		  if( FALSE == ReadFile(hbud, OB, (DWORD)sizeof(struct tagOBUDRESULTS), &dwBytesRead1, NULL) )
			MessageBox(NULL,"Can't read first part","Reading DAT", MB_ICONEXCLAMATION|MB_OK);

		  if( FALSE == ReadFile(hbud, OM, (DWORD)sizeof(struct tagOMEASURE), &dwBytesRead2, NULL) )
			MessageBox(NULL,"Can't read second part","Reading DAT", MB_ICONEXCLAMATION|MB_OK);
	  }
	  else
	  {
		  if( FALSE == ReadFile(hbud, pBudResults, (DWORD)sizeof(struct tagBUDRESULTS), &dwBytesRead1, NULL) )
			MessageBox(NULL,"Can't read first part","Reading DAT", MB_ICONEXCLAMATION|MB_OK);

		  if( FALSE == ReadFile(hbud, M, (DWORD)sizeof(struct tagMEASURE), &dwBytesRead2, NULL) )
			MessageBox(NULL,"Can't read second part","Reading DAT", MB_ICONEXCLAMATION|MB_OK);
	  }
	  CloseHandle(hbud) ;

	  InterpretData(oldstyle) ;

}
	 
void InterpretData(int oldstyle)
{
  LPBUDRESULTS  B ;
 LPOBUDRESULTS OB ;
     LPMEASURE  M ;
    LPOMEASURE OM ;
		 POINT  p ;
		DPOINT dp ;
		   int  i ;


	B = pBudResults ;
	M = pMeasure ;
   OB = pOBudResults;
   OM = pOMeasure ;
	
	  xsa = oldstyle ? OB->SubImageX : pBudResults->SubImageX ;
	  ysa = oldstyle ? OB->SubImageY : pBudResults->SubImageY ;
	   ws = oldstyle ? OB->SubImageW : pBudResults->SubImageW ;
	  xsb = xsa + ws ;
	   hs = oldstyle ? OB->SubImageH : pBudResults->SubImageH ;
	  ysb = ysa + hs ;
   Levels = oldstyle ? OB->NumHyts   : pBudResults->NumHyts  ;

   // if the co-ordinates of the Top Left Corner are not zero,
   // then the image was resized. (NOT foolproof!?!? The TLC
   // of the inset *might* have been set to zero?)

	  if (xsa != 0 || ysa != 0) resized = 1 ;

	  if (resized)
	  PlayList[clips++] = 11 ;

// if a pole position has other than the default co-ordinates,
// then that pole was set. Again, not foolproof, but the risk
// of the defaults actually having been selected for poles is
// exceedingly small!

if (oldstyle)
{		   
if (OB->BudTopPoleX != TPxdefault || OB->BudTopPoleY != TPydefault)
	TOPSET = 1 ;
if (OB->BudBotPoleX != BPxdefault || OB->BudBotPoleY != BPydefault)
	BOTSET = 1 ;
}
else
{
if (pBudResults->BudTopPoleX != TPxdefault || pBudResults->BudTopPoleY != TPydefault)
	TOPSET = 1 ;
if (pBudResults->BudBotPoleX != BPxdefault || pBudResults->BudBotPoleY != BPydefault)
	BOTSET = 1 ;
}

if (TOPSET && BOTSET)
{
    PlayList[clips++] = 18 ;

	    dp.x = pBudResults->BudTopPoleX ;
		dp.y = pBudResults->BudTopPoleY ;
	    ImgToCli(&p, &dp) ; 	  

				 SetRect(&rcTpole,
					 p.x - 10,
					 p.y - 10,
					 p.x + 10,
					 p.y + 10
					 ) ;

	    dp.x = pBudResults->BudBotPoleX ;
		dp.y = pBudResults->BudBotPoleY ;
	    ImgToCli(&p, &dp) ;
		
				 SetRect(&rcBpole,
					 p.x - 10,
					 p.y - 10,
					 p.x + 10,
					 p.y + 10
					 ) ;
}
else
if (TOPSET && !BOTSET)
{
	PlayList[clips++] = 15 ;

	    dp.x = pBudResults->BudTopPoleX ;
		dp.y = pBudResults->BudTopPoleY ;
	    ImgToCli(&p, &dp) ;
		
				 SetRect(&rcTpole,
					 p.x - 10,
					 p.y - 10,
					 p.x + 10,
					 p.y + 10
					 ) ;
}
else
if (!TOPSET && BOTSET)
{
	PlayList[clips++] = 16 ;

	    dp.x = pBudResults->BudBotPoleX ;
		dp.y = pBudResults->BudBotPoleY ;
	    ImgToCli(&p, &dp) ;
		
				 SetRect(&rcBpole,
					 p.x - 10,
					 p.y - 10,
					 p.x + 10,
					 p.y + 10
					 ) ;
}
else
if (!TOPSET && !BOTSET)
{
    PlayList[clips++] = 17 ;
}


   // if any level is not marked BOTH,
   // then not all levels were measured.
	  
   // if no level is marked NONE,
   // then at least one measurement was taken.

   if (oldstyle)
	  {
	  for (i = 1, AllDone = 1, SomeDone = 0 ; 
	       i <= OB->NumHyts ; i++ )
		   {
		   if ((EdgeDone[i] = OB->Edges[i]) != BOTH) AllDone = 0 ;
		   if ( EdgeDone[i] != NONE) SomeDone = 1 ;
		   }
      }
   else
      { 
	  for (i = 1, AllDone = 1, SomeDone = 0 ; 
	       i <= pBudResults->NumHyts ; i++ )
		   {
		   if ((EdgeDone[i] = pBudResults->Edges[i]) != BOTH) AllDone = 0 ;
		   if ( EdgeDone[i] != NONE) SomeDone = 1 ;
		   }
      }

		   if (AllDone)
			   PlayList[clips++] = 12 ;
		   else
		   if (SomeDone)
			   PlayList[clips++] = 13 ;
		   else
			   PlayList[clips++] = 14 ;
}


void SetDragHandles( int placing )
{
// Set up Pole drag-handles
 POINT p ;
DPOINT dp ;
   int xt, yt, xb, yb ;
if (TOPSET || (placing && SETTOP))
    {
	    dp.x = pBudResults->BudTopPoleX ;
		dp.y = pBudResults->BudTopPoleY ;
	    ImgToCli(&p, &dp) ; 	  
    }
	else   // use default
	{
		dp.x = TPxdefault ;
		dp.y = TPydefault ;
	    ImgToCli(&p, &dp) ; 
	}
	  xt = p.x - 6 ;
	  yt = p.y - 25 ;
	SetRect(&rcTpole,
		    xt + 10,
	        yt,
			xt + 30,
			yt + 20
			) ;
	SetRect(&rcTPico,
		    xt,
			yt,
			xt + 32,
			yt + 32
			) ;
if (BOTSET || (placing && !SETTOP))
    {
	    dp.x = pBudResults->BudBotPoleX ;
		dp.y = pBudResults->BudBotPoleY ;
	    ImgToCli(&p, &dp) ; 
	}
	else    // use default
	{ 
		dp.x = BPxdefault ;
		dp.y = BPydefault ;
	    ImgToCli(&p, &dp) ; 
	}
	  xb = p.x - 6 ;
	  yb = p.y - 6 ; 
	SetRect(&rcBpole,
		    xb + 10,
	        yb + 10,
			xb + 30,
			yb + 30
			) ;
	SetRect(&rcBPico,
		    xb,
			yb,
			xb + 32,
			yb + 32
			) ;						 
}

void DrawDragHandles( HWND hWnd )
{
	HDC hdc ;
	hdc = GetDC(hWnd) ;
    DrawIcon(hdc, rcTPico.left, rcTPico.top, icoTP) ;
    DrawIcon(hdc, rcBPico.left, rcBPico.top, icoBP) ;
	ReleaseDC(hWnd, hdc) ;
}

long CALLBACK ListingsProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
	PAINTSTRUCT ps ;
	HDC hdc ;
	HFONT oFn ;

	char txt[] = "Listing Window awaits implementation." ;

	switch(message)
	{

	case WM_COMMAND:

		switch(LOWORD(wParam))
		{
			// test the tool bar

		case IDM_TB1:
			MessageBeep(MB_ICONASTERISK) ;
			break ;

		case IDM_TB2:
			MessageBeep(MB_OK) ;
			break ;

		case IDM_TB3:
			MessageBeep(MB_ICONHAND) ;
			break ;

		case IDM_TB4:
			MessageBeep(MB_OK) ;
			break ;

		case IDM_TB5:
			MessageBeep(MB_ICONEXCLAMATION) ;
			break ;

		default:
			break ;
		}
		break ;

	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps) ;
		ShowWindow(hWndTB, SW_SHOW) ; // display the toolbar
		oFn = SelectObject(hdc, hfnt) ;
		SetBkColor(hdc, RGB(192, 192, 192)) ;
		SetBkMode(hdc, OPAQUE) ;
		TextOut(hdc,40,100,txt,strlen(txt)) ;
		SelectObject(hdc, oFn) ;

		EndPaint(hWnd, &ps) ;
		break ;

        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
	}
 return ((long)NULL) ;
}

/*********************************************************************
              Bud-Data Collation Window Procedure										 
 *********************************************************************/
long CALLBACK CollateProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
	PAINTSTRUCT ps ;
		    HDC hdc, hmemDC ;
		 BITMAP bm ;
		HBITMAP Obm ;

	     int UserSays ;
	   POINT mouse, cpt, cupt ;
static       ITM = 0, LST = 0, AST = 0, AGR = 0, FOU = 0 ;

	switch(message)
	{

	case WM_NCHITTEST: // works for any mouse event in this window

	    if (hWnd != CurrentWindow)
	    {
		  SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		  CurrentWindow = hWnd ;
	    }

	    // The hit test must be passed
	    // to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

	case WM_COMMAND:

		switch(LOWORD(wParam))
		{

		 case WM_MOUSEGONE:
		   if (CurrentTip != (HWND)NULL)
			   RemoveTip() ;
		   return 0L ;

		case IDC_GET_ITEMS_BUTTON:
		case IDM_GET_ITEMS:
			    
			    collating ^= 1 ;
			    ITM = collating  ;
				ivrc(hWnd,&rctl[Itm],FALSE) ;

				UserSays = DialogBox(hInst,
					      MAKEINTRESOURCE(IDD_COLLATE),
						  hWnd,
						  CollateDlgProc) ;

				if (UserSays == IDOK)
				{
				  StartWait() ;
				  Inventory(BudSearch) ;
				  EndWait() ;
				  collating = 0 ;
				  ITM = collating ;
				  ivrc(hWnd,&rctl[Itm],FALSE) ;
				}

				if (UserSays == IDCANCEL)
				{
				  collating = 0 ;
				  ITM = collating ;
				  ivrc(hWnd,&rctl[Itm],FALSE) ;
				}

			return 0 ;
			
		case IDM_ARCHIVIST:	// shows/hides the Archivist
			ACV ^= 1 ;
			ivrc(hWnd,&rctl[Acv],FALSE) ;
			if (ACV)
			{
				// if never seen, create it now
				if (hArcDlg == (HWND)NULL)
					hArcDlg = CreateDialog(
						hInst,
						MAKEINTRESOURCE(IDD_ARCHIVIST),
						hWndCtrl,
						ArchivistDlgProc ) ;
					ShowWindow(hArcDlg, SW_SHOW) ;	// show the Archivist
					SetWindowPos(hArcDlg, HWND_TOP,	// be sure it comes up tops
					         0,0,0,0,
							 SWP_NOSIZE|SWP_NOMOVE) ;
					SetTimer(hWndCtrl, IDT_HIT_TIMER, 100, NULL ) ;	// start the hit-timer			
			}
			else
			{
				ShowWindow(hArcDlg, SW_HIDE) ;		 // hide the Archivist
			    KillTimer(hWndCtrl, IDT_HIT_TIMER) ; // stop the hit-timer 
				UpdateWindow(hWndBud) ;				 // be sure the underlying windows re-appear
				UpdateWindow(hWndRslt) ;
			}

			return 0 ;

		case IDC_LIST_ITEMS_BUTTON:
		case IDM_DO_LISTING:
			dolisting ^= 1 ;
			LST = dolisting ;
			ivrc(hWnd,&rctl[Lst],FALSE) ;

			if (dolisting)
			{
				ShowWindow(hWndLists, SW_SHOW) ;
				BringWindowToTop(hWndLists);
			}
			else
				ShowWindow(hWndLists, SW_HIDE) ;

			return 0 ;

		case IDC_ASTRONOMY_BUTTON:
		case IDM_ASTRONOMY:
			astronomy ^= 1 ;
			AST = astronomy ;
			ivrc(hWnd,&rctl[Ast],FALSE) ;

			UserSays = DialogBox(hInst,
					      MAKEINTRESOURCE(IDD_LUNAR_ALIGN),
						  hWnd,
						  AlignDlgProc) ;

				if (UserSays == IDOK)
				{
				  AST = astronomy = 0 ;
				  ivrc(hWnd,&rctl[Ast],FALSE) ;
				}

				if (UserSays == IDCANCEL)
				{
				  AST = astronomy = 0 ;
				  ivrc(hWnd,&rctl[Ast],FALSE) ;
				}

			return 0 ;

		case IDC_FOURIER_BUTTON:
		case IDM_DO_FOURIER:

			fourierop ^= 1 ;
			FOU = fourierop ;
			ivrc(hWnd,&rctl[Fou],FALSE) ;
			if (fourierop)
			{
			ShowWindow(hWndArch,SW_SHOW) ;
			SetWindowPos(hWndArch, HWND_TOP,
					         0,0,0,0,
							 SWP_NOSIZE|SWP_NOMOVE) ;
			}
			else
			{
			if (FouSetUp)
			SendMessage(hWndArch,WM_COMMAND,IDM_SHOW_SETUP,0L) ;
			ShowWindow(hWndArch,SW_HIDE) ;
			}

		return 0 ;

		default: break ;
		}
		break ;

	case WM_TIMER:
			switch(wParam)
			{
			case IDT_VOCTIMER:
			GetCursorPos(&cupt) ;
			ScreenToClient(hWnd,&cupt) ;
			if (PtInRect(&rctl[UseBtn],cupt))
			{
				PlaySound(szVocTipWav[UseBtn], NULL, SND_ASYNC) ;
			}
			KillTimer(hWnd,VTim) ;
			break ;

			case IDT_TIPDWELL:
			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 DestroyWindow(hWndInfo[UseCtl]) ;
				 CurrentTip = (HWND)NULL ;
				 hWndOfCurrentTip = (HWND)NULL ;
			 }
			 KillTimer(hWnd, IDT_TIPDWELL) ;
			 Dwelling[UseCtl] = 0 ;
				return 0L ;

			case IDT_TIPDEFER:
			 KillTimer(hWnd,IDT_TIPDEFER) ;
			 Deferred[UseCtl] = 0 ;

			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 PutTip(hWnd, 0, 3) ;
			 }
			    break ;

			default:
				break ;
			}
			return 0L ;
		break ;

	case WM_MOUSEMOVE:

		mouse.x = LOWORD(lParam) ;
		mouse.y = HIWORD(lParam) ;

		if (showtips || sounds)
		{
			GetCursorPos(&cpt) ;
			ScreenToClient(hWnd,&cpt) ;
			GetTip( hWnd, Itm, Fou, cpt ) ;
		// Vocals not yet supplied.
		// Causes crash if used.
		//if (sounds)
		//	GetVoc( hWnd, Itm, Fou, cpt ) ;
		}
		break ;

	case WM_LBUTTONDOWN:

		mouse.x = LOWORD(lParam) ;
		mouse.y = HIWORD(lParam) ;

		if (PtInRect(&rctl[Itm], mouse))
		{
			SendMessage(hWnd, WM_COMMAND, IDM_GET_ITEMS, 0L) ;
		}

		if (PtInRect(&rctl[Lst], mouse))
		{
			Clicked[Lst] = 1 ;
			KillTip(hWnd, Lst) ;
			SendMessage(hWnd, WM_COMMAND, IDM_DO_LISTING, 0L) ;
		}

		if (PtInRect(&rctl[Ast], mouse))
		{
			Clicked[Ast] = 1 ;
			KillTip(hWnd, Ast) ;
			SendMessage(hWnd, WM_COMMAND, IDM_ASTRONOMY, 0L) ;
		}

		if (PtInRect(&rctl[Acv], mouse))
		{
			Clicked[Acv] = 1 ;
			KillTip(hWnd, Acv) ;
			SendMessage(hWnd, WM_COMMAND, IDM_ARCHIVIST, 0L) ;
		}

		if (PtInRect(&rctl[Fou], mouse))
		{
			Clicked[Fou] = 1 ;
			KillTip(hWnd, Fou) ;
			SendMessage(hWnd, WM_COMMAND, IDM_DO_FOURIER, 0L) ;
		}

		break ;

	case WM_PAINT:
            hdc = BeginPaint(hWnd, &ps) ;
         hmemDC = CreateCompatibleDC(hdc) ;
         GetObject(bmITM, sizeof(BITMAP), &bm ) ;
            Obm = SelectObject(hmemDC, bmITM) ;

	   if( !ITM )                            // for "Select Items" button
               SelectObject(hmemDC, bmITM) ; // show enabled but unselected
            else
               SelectObject(hmemDC, bmITMO) ;// show selected

               BitBlt(hdc, rctl[Itm].left,	  // show button
                           rctl[Itm].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !LST )                            // for "List Items" button
               SelectObject(hmemDC, bmLST) ; // show enabled but unselected
            else
               SelectObject(hmemDC, bmLSTO) ;// show selected

               BitBlt(hdc, rctl[Lst].left,	  // show button
                           rctl[Lst].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !AST )                            // for "Astromomy" button
               SelectObject(hmemDC, bmAST) ; // show enabled but unselected
            else
               SelectObject(hmemDC, bmASTO) ;// show selected

               BitBlt(hdc, rctl[Ast].left,	  // show button
                           rctl[Ast].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;


	   if( !ACV )                            // for "Archivist" button
               SelectObject(hmemDC, bmACV) ; // show enabled but unselected
            else
               SelectObject(hmemDC, bmACVO) ;// show selected

               BitBlt(hdc, rctl[Acv].left,	  // show button
                           rctl[Acv].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;


	   if( !FOU )                            // for "Fourier" button
               SelectObject(hmemDC, bmFOU) ; // show enabled but unselected
            else
               SelectObject(hmemDC, bmFOUO) ;// show selected

               BitBlt(hdc, rctl[Fou].left,	  // show button
                           rctl[Fou].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

		SelectObject(hmemDC, Obm) ;
		DeleteDC(hmemDC) ;
		EndPaint(hWnd, &ps) ;
		break ;

	case WM_CREATE:
		bmITM  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GET_ITEMS)) ;
		bmITMO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GET_ITEMS_ON)) ;
		bmLST  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_LIST_ITEMS)) ;
		bmLSTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_LIST_ITEMS_ON)) ;
		bmAST  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ASTRONOMY)) ;
		bmASTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ASTRONOMY_ON)) ;
		bmACV  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ARCHIVIST)) ;
		bmACVO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ARCHIVIST_ON)) ;
		bmFOU  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_FOURIER)) ;
		bmFOUO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_FOURIER_ON)) ;
		return 0L ;
		break ;

	case WM_DESTROY:
		DeleteObject(bmITM) ;
		DeleteObject(bmITMO) ;
		DeleteObject(bmLST) ;
		DeleteObject(bmLSTO) ;
		DeleteObject(bmAST) ;
		DeleteObject(bmASTO) ;
		DeleteObject(bmACV) ;
		DeleteObject(bmACVO) ;
		DeleteObject(bmFOU) ;
		DeleteObject(bmFOUO) ;
		return 0L ;
		break ;


        break ;

        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
	}
 return ((long)NULL) ;
}

/****************************************************
 re-display a 32x32 grabbed patch of on-screen window
 ****************************************************/

HBITMAP PutPatch
(
    HWND hWnd,
 HBITMAP hBm,
     int w,
	 int h,
     int x,
     int y
)
{
	HDC hdc, hmDC ;
HBITMAP oB ;

	 hdc = GetDC(hWnd) ;
	hmDC = CreateCompatibleDC(hdc) ;
	  oB = SelectObject(hmDC, hBm) ;

 BitBlt(hdc, x, y, w, h, hmDC, 0, 0, SRCCOPY) ;

 SelectObject(hmDC, oB) ;
 DeleteDC(hmDC) ;
 ReleaseDC(hWnd, hdc) ;
 DeleteObject(hBm) ;     // should prevent memory leak
 return hBm ;			 // return the _invalid_ handle
}

/****************************************
  Grab a 32x32 patch of on-screen window
 ****************************************/
HBITMAP GrabPatch
(
HWND hWnd,
 int w,
 int h,
 int x,
 int y
)
{
	HDC hdc, hmDC ;
HBITMAP hBm, oB ;

	 hdc = GetDC(hWnd) ;
	hmDC = CreateCompatibleDC(hdc) ;
	 hBm = CreateCompatibleBitmap(hdc, w, h) ;
	  oB = SelectObject(hmDC, hBm) ;

BitBlt(hmDC, 0, 0, w, h, hdc, x, y, SRCCOPY) ;

hBm = SelectObject(hmDC, oB) ;

DeleteDC(hmDC) ;
ReleaseDC(hWnd, hdc) ;

return hBm ;
}

HBITMAP GetZoomPatch
(
HWND hWnd,	// source window
 int x,		// cursor pos
 int y,
 int w,		// grab-region at cursor
 int h
)
{
	     HDC hdc, hmemdc ;
	 HBITMAP oBm, hBm ;

// get the source window DC, and set its mapping mode
	    hdc = GetDC(hWnd) ; SetMapMode(hdc, MM_TEXT) ;

// get a mem DC compatible with the source window
	 hmemdc = CreateCompatibleDC(hdc) ;

// get the handle of a bitmap of the required dimensions
// and compatible with the source window 
	    hBm = CreateCompatibleBitmap(hdc, w, h) ;

// Select this bit map into the mem DC
	    oBm = SelectObject(hmemdc, hBm) ;

// Copy patch into the mem DC
	 BitBlt(hmemdc, 0, 0, w, h, hdc, x - w/2, y - h/2, SRCCOPY) ;

// and get its handle
	    hBm = SelectObject(hmemdc, oBm) ;

// clean up
	 DeleteDC(hmemdc) ;
	 ReleaseDC(hWnd, hdc) ;

// send bitmap home
	return hBm ;
}

/********************************************************************
                BudWndProc
*********************************************************************/
long CALLBACK  BudWndProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
 PAINTSTRUCT ps ;
         HDC hdc, hmemDC, hmemDCc ;
      BITMAP bm ;
     HBITMAP oBm, ozBm, oBmc, hBm, hzBm, bmap ;
       HFONT oFnt ;
    OFSTRUCT of ;
static  HPEN oPen ;
static POINT pt, pd, pz, pt1, pt2, pt3, client, Bf, Sc ;
static POINT ptstart, ptprevend, ptnow, curpt, crpt, box, cpt, cupt, tpt ;
static  BOOL prev = FALSE ;
static  RECT rcimgscr ;
	  DPOINT p, p2, image ;
         HDC hdc1, hrdc, hzDC, hzmemdc ;
     HCURSOR oldCursor ;
   LPMEASURE M ;
LPBUDRESULTS B ;
        SIZE sz ;
static  BYTE FAR * ptr ;
static char * filetitle ;
static  TXT  T ;
        char pos[100] ;
		char string[180] = "\0" ;
		char * kind[] = { "in", "mm", "iu" } ;
      static Btn ;
		 int L, button, oldbutton ;
		 int xa, ya, xb, yb ;
		 int UserSays ;
	  double factor, grad, icept, x1, x2, y1, y2, D ;
	  
	  static double oxm, oym, oxp, oyp, oxp1, oyp1 ;
	  static double Lam, oLam, ALam, oALam ;
	  static double  oRad, oARad ;

      static double MRTopX, MRTopY ;	// most recently recorded high pole position
      static double MRBotX, MRBotY ;	// most recently recorded low  pole position

	  static double MRUTopX, MRUTopY ;	// most recently used high pole position
	  static double MRUBotX, MRUBotY ;	// most recently used low  pole position

      static double MRULftTkX, MRULftTkY ;	// most recently used left  track start
	  static double MRURytTkX, MRURytTkY ;	// most recently used right track start

  static i, j, xo, yo, oxo, oyo, xr, yr, oxr, oyr, ox1, oy1, xcur, k = 0 ;
  static dragtop, dragbot, dx, dy ;
  static Ep, idx, BEp, Bidx, xrs, yrs  ;
  static oXms, oYms, Ym, oYm, previousline, Range, g, first, last ;
  static onLeft, xplace, yplace ;
  static arm = 8, oarm = 8 ;
  static zw, zh, zwz, zhz, zdx, zdy ;
  static CurInImg = 0, CurAtPole = 0, wasin = 0, ignore_mouse = 0, Confirm, dragstarted ;
  static     LSC = 0,   GRA = 0,   REZ = 0,    LSA = 0,    LSR = 0,  LSG = 0,  LSB = 0 ; 
  static     LLV = 0,   HIP = 0,   LOP = 0,   CAL1 = 0,   CAL2 = 0 ;
  static     ACP = 0,   PRM = 0 ;


			             M = pMeasure ;

   switch (message)
    {
		case WM_NCHITTEST: // works for any mouse event in this window

	if (hWnd != CurrentWindow) // mouse has just arrived in this window
	{
		// tell the abandoned window that the mouse has left it,
		// so that it may dispose of any tip that happens to be pending
		// or showing there.
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		// and make this window the current mouse window, so that it
		// may service any tips that may be wanted.
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

          case WM_COMMAND:       /* message: command from application menu */
        
         switch(LOWORD(wParam))
         {
		 case WM_MOUSEGONE:  // Oh, Oh! Mousey has left us. Kill any tip now on the go here.
		   if (CurrentTip != (HWND)NULL)
		   RemoveTip() ;
		   return 0L ;

          case IDM_SHOWBM:
          AdjustDisplays() ;
		  if (!batching)
		  {
			stored = 0 ;
			GetLineStorage() ;
		  }
          ivrc(hWnd, NULL, TRUE) ;
          UpdateWindow(hWnd) ;
 		  ivrc(hWndRslt,NULL,TRUE) ;
		  UpdateWindow(hWndRslt) ;
		  break ;

		  case LEVEL_PICKED:
		  break ;
		  
		  case RESTORE_IMAGE:		      // Alt + r
			// if not scanning or setting,
			// and image has been resized, ALT + R causes
			// reversion to original bitmap.
  if (resized & !scanning & !setpole & !setlevels)
			{
	           OFSTRUCT of ;
			      HFILE hTrk ;

	           M = pMeasure ;
			   B = pBudResults ;

			 	  pBudResults->SubImageW =  ws = (int)dibwid ;
				  pBudResults->SubImageH =  hs = (int)dibhyt ;
				  pBudResults->SubImageX = xsa = 0 ;
				  pBudResults->SubImageY = ysa = 0 ;
				           xsb = ws ;
						   ysb = hs ;
				  pBudResults->BudMag    = pmag = 1.0 ;

				resized = reset ;
				toArchive = set ;
			// we will need to redo pole placement,
			// remeasure the bud,
			// and remove the track file if it exists.
			    for ( i = 1 ; i <= MAXLEVELS ;
				REdgeOrg[i] = LEdgeOrg[i] = EdgeDone[i++] = NONE) ;
				Blink = SetTimer(hWndBud, IDT_BTIMER, tBlink, NULL) ;
				TOPSET = BOTSET = reset ;
				if ((hTrk = OpenFile(szTrkPath, &of, OF_EXIST)) != HFILE_ERROR)
				{
					 hTrk = OpenFile(szTrkPath, &of, OF_DELETE) ;
				}

				AdjustDisplays() ;
				if (!batching)
				{
				stored = 0 ;
				GetLineStorage() ;
				}

				ivrc(hWnd,    NULL,TRUE) ; // prewipe all client area
				ivrc(hWndRslt,NULL,TRUE) ;
				msgbox = 1 ;
				MessageBox(hWnd,
               "Restoring the image has invalidated\n" \
               "the Pole placements and any measurements\n" \
               "which may have been made.\n\n" \
               "Please place both poles again.",
               "Original Image Restored",MB_ICONINFORMATION | MB_OK ) ;
				msgbox = 0 ;
				SendMessage(hWndRslt, WM_RESET, 0, 0L) ;
			}
				else
				{
					msgbox = 1 ;
					MessageBox(NULL, "Oops! Not right now!", "Image Restore by ALT-R", MB_OK) ;
					msgbox = 0 ;
				}
			  break ;

		  case TOGGLE_SCAN:				  // Ctrl + s
			  if(!setlevels)
			  {
                LSC ^= 1 ;    //toggle scanning button state
		   
			//if not scanning and graphing on, turn off graphing. 
		   if (graphing && !LSC)
		   	   SendMessage(hWnd,WM_COMMAND,TOGGLE_GRAPHS,0L) ;
		    
           scanning = LSC ; //match flag to button state
			   
		   if (!LSC) wide = 0 ;

           ivrc(hWnd,&rctl[Lsc],FALSE) ; //indicate button state

			 if (scanning)
			 {
			  if (scancolour == 0)
			    { LSA = 1 ; LSR = 0 ; LSG = 0 ; LSB = 0 ; }
			  if (scancolour == 1)
			    { LSA = 0 ; LSR = 1 ; LSG = 0 ; LSB = 0 ; }
			  if (scancolour == 2)
			    { LSA = 0 ; LSR = 0 ; LSG = 1 ; LSB = 0 ; }
			  if (scancolour == 3)
			    { LSA = 0 ; LSR = 0 ; LSG = 0 ; LSB = 1 ; }
			 }
			 else
			  { LSA = 0 ; LSR = 0 ; LSG = 0 ; LSB = 0 ; }

		   ivrc(hWnd, &rctl[Scc], TRUE) ;
           UpdateWindow( hWnd ) ;
			  }
			  break ;

		  case TOGGLE_COLOUR:				    // Ctrl + C
			  {
			   which++ ;
			   if (which > 2) which = 0 ;
			 if ( which == SIGNIF )
			 {
				 if (SigDlg == (HWND)NULL)
				 {
				 SigDlg = CreateDialog(
					 hInst,
					 MAKEINTRESOURCE(IDD_SIGPATCH),
					 hWndBud,
					 SigPatch) ;
				 }
				 ShowWindow(SigDlg, SW_SHOW) ;

				 if (!ImgSig)
				 {
				 ImageSig(xpch, ypch) ;
				 ImgSig = 1 ;
				 }
			 }
			 else
			 if (SigDlg != (HWND)NULL)
			 ShowWindow(SigDlg, SW_HIDE) ;

			 ivrc(hWnd,&rctl[Gry],FALSE) ;
			 ivrc(hWnd,&rcimg,FALSE) ; // show
			 ivrc(hWndRslt, NULL, FALSE) ;
			  }
			 break ;

		  case TOGGLE_GRAPHS:			// Ctrl + g
			  if (scanning)
			 {
			 GRA ^= 1 ;
			 graphing = GRA ;
			 if (!graphing && ISONPEAK) ISONPEAK = 0 ;
			 ivrc(hWnd,&rctl[Gra],FALSE) ;
			 SendMessage(hWndScan,WM_COMMAND,IDM_SHOW_SCAN,0L) ;
			 }
			  break ;

		  case CALIBRATE_MEASURE_ONE:	 // Alt + 1 key
			 // if we're scanning, turn it off
			 if (scanning) 
			 SendMessage(hWnd, WM_COMMAND, TOGGLE_SCAN, 0L) ;

			       CAL1 ^= 1 ;             // toggle button
			 calibrating = SETCAL1 = CAL1 ;// (re)cal. if pressed
			 if (CAL1)					   // if (re)cal,
				 CAL1SET = reset ;         // flag as uncalib'd
			  calibrated = reset ;

			 ivrc(hWnd,&rctl[Ca1],FALSE) ;
			 UpdateWindow( hWnd ) ;
			  break ;

		  case CALIBRATE_MEASURE_TWO:	  // Alt + 2 key
			 if (scanning)
			 SendMessage(hWnd, WM_COMMAND, TOGGLE_SCAN, 0L) ;

			        CAL2 ^= 1 ;			  // toggle button
			 calibrating  =  CAL2 ;		  // (re)cal if pressed
			     SETCAL1  = !CAL2 ;
			 if (CAL2)					  // if (re)cal.,
				  CAL2SET = reset ;		  // flag as uncalibrated
			   calibrated = reset ;

			 ivrc(hWnd,&rctl[Ca2],FALSE) ;
			 UpdateWindow( hWnd ) ;
			  break ;

		  case AUTOMEAS_BUD:
			  AUT ^= 1 ;					// toggle the button flag
			  autotrack = AUT ;				// match action flag to button state
			  if (gotimage && autotrack)	// if we have an image and want to track it
			  {
			   // if it is not already autotracked, set up for it
				  if (!autotracked)
				  {
					   
				    // make room for the tracking data
				       if (FreeTrackMemory(&Tk))
						   AllocTrackHyts(&Tk, hs) ;
					   else
						   MessageBox(NULL,
						   "Track Memory unallocated",
						   "1st Tracking", MB_OK) ;

				    // turn on scanning if it's off
				       if (!scanning)
				       {
				        SendMessage(hWnd,WM_COMMAND,TOGGLE_SCAN,0L) ;
				        ivrc(hWnd, &rctl[Lsc], FALSE) ; // refresh the button
				       }
				  }
				  else
			  // if it's already autotracked,
			  // then cancel all to begin again
			      {	
					if (FreeTrackMemory(&Tk))
						AllocTrackHyts(&Tk, hs) ;
					   else
						   MessageBox(NULL,
						   "Track Memory unallocated",
						   "Re-Tracking", MB_OK) ;
					  
				   autotracked = 0 ;
				   autolftdone = ALF = 0 ;
					 ivrc(hWnd,&rctl[Alf],FALSE) ;
				   autorytdone = ART = 0 ;
					 ivrc(hWnd,&rctl[Art],FALSE) ;
			      }
			  }
			  ivrc(hWnd,&rctl[Aut],FALSE) ;
			  break ;


		  case AUTOMEAS_LFT: 
			  if (autotrack)
			  {
			  autodolft ^= 1 ;
			  ALF = autodolft ;
			  // turn off other button
			  if (autodolft) autodoryt = ART = 0 ;
			  // if to track left side and already tracked,
			  // cancel tracking for redo
			  if (autolftdone && autodolft)
			  {
				  autolftdone = 0 ;
				  // this action means bud is not completely tracked
				  if (autotracked)
				  {
					  autotracked = 0 ;
					  ivrc(hWnd,&rctl[Aut],FALSE) ;
				  }
			  }
			  ivrc(hWnd,&rctl[Alf],FALSE) ;
			  ivrc(hWnd,&rctl[Art],FALSE) ;
			  }
			  break ;

		  case AUTOMEAS_RYT: 
			  if (autotrack)
			  {
			  ART ^= 1 ;
			  autodoryt = ART ;
			  // turn off other button
			  if (autodoryt) autodolft = ALF = 0 ;
			  // if to track right side and already tracked,
			  // cancel tracking for redo
			  if (autorytdone && autodoryt)
			  {
				  autorytdone = 0 ;
				  // this action means bud is not completely tracked
				  if (autotracked)
				  {
					  autotracked = 0 ;
					  ivrc(hWnd,&rctl[Aut],FALSE) ;
				  }
			  }
			  ivrc(hWnd,&rctl[Art],FALSE) ;
			  ivrc(hWnd,&rctl[Alf],FALSE) ;
			  }
			  break ;

		  case SET_TRACK_PARMS: // the tracking parameter dialogue box
			  PRM ^= 1 ;
			  ivrc(hWnd,&rctl[Prm],FALSE) ;
			  if (PRM)
			  {
			   if (TkParmDlg == (HWND)NULL)
		       TkParmDlg = CreateDialog(
			                            hInst,
			                            MAKEINTRESOURCE(IDD_TRACKING_PARMS),
			                            hWnd,
			                            TkParmDlgProc
			                           ) ;

				  ShowWindow(TkParmDlg,SW_SHOW) ;
			  }
			  else
			  {
				  ShowWindow(TkParmDlg,SW_HIDE) ;
			  }

			  break ;

		  case ACCEPT_TRACK:
			  ACP = 0 ;
			  if (autodolft)
			  {
				  ALF = autodolft = 0 ;
				  autolftdone = 1 ;
				  ivrc(hWnd,&rctl[Alf],FALSE) ;
				  Tk.Blcapt = LinkTrackPoints(&Tk, LEFT) ;
			  }

			  if (autodoryt)
			  {
				  ART = autodoryt = 0 ;
				  autorytdone = 1 ;
				  ivrc(hWnd, &rctl[Art], FALSE) ;
				  Tk.Brcapt = LinkTrackPoints(&Tk, RIGHT) ;
			  }
			  ivrc(hWnd, &rctl[Acp], FALSE) ;

			  if (autolftdone && autorytdone)
			  {
					 LPSUITE sui ;
						char szTkpth[256] ;
						char szTail[100] ;
						char * d ;
						 int u, i, n, ok ;

/***** for ready reference
typedef struct tagIDS
		{
	UINT pfxID ;
	UINT imgID ;
	UINT imgpth ;
	UINT iniID ;
	UINT inipth ;
	UINT datID ;
	UINT datpth ;
	UINT trkID ;
	UINT trkpth ;
 LPSUITE pS ;
		} IDS, * LPIDS ; // a copy for reference

  IDS  I ;
LPIDS pI = &I ;
****/
				sui = A.pSuiteperpfx[I.pfxID][UseSuite] ; // get the current suite

				  autotracked = 1 ;
					showTrack = 1 ;
					//autotrack = 0 ;
				          AUT = 0 ;

		//  create a track file if none exists.
		// (this is where to involve the Suite.)

					if (sui->iTRKpth < 0) // if there is no track path in the current suite
					{
						strcpy(szTail, sui->desc ) ;	// get the suite's tail
						strcpy(szTkpth, AllTrk) ;		// form a path to the TRKs...
						strcat(szTkpth, szTail) ;		// ...in this suite
						if (!(_mkdir(szTkpth)))			// make a TRK folder corresponding to the Suite
						{
							// add its path to the global path list
							I.trkpth = A.iGpthIDs ;
							d = (char *)GlobalAlloc(GPTR,(strlen(szTkpth) + 2) * sizeof(char)) ;
							strcpy(d, szTkpth) ;
							A.szKnownpth[I.trkpth] = d ;
							sui->iTRKpth = I.trkpth ;			// install new TRK path in the Suite 
							incpth("New track: saving")  ;		// A.iGpthIDs++ ;
						// acquaint the PFX ID with the TRK PTH ID
						u = A.iNumtrkpthsperpfx[I.pfxID]  ;
						A.iTrkpthperpfx[I.pfxID][u] = I.trkpth ;
						A.iNumtrkpthsperpfx[I.pfxID]++ ;
						}
					}
						// form track file name and path to it
						strcpy(szTrkPath, A.szKnownpth[sui->iTRKpth]) ;
						strcpy(szTrkFile, AddExt(DropPath(szFile),".trk")) ;
						strcat(szTrkPath, szTrkFile) ;

						// have we seen this track file before?
						for (i = ok = 0, n = A.iTrkIDs ; i < n ; i++)
						{
							if (!strcmp(_strlwr(szTrkFile), _strlwr(A.szKnowntrk[i])))
							{ ok = 1 ; I.trkID = i ; break ;} // seen
						}
						if (!ok)	// not seen
						{
							u = I.trkID = A.iTrkIDs ;
							d = (char *)GlobalAlloc(GPTR,(strlen(szTrkFile) + 2) * sizeof(char)) ;
							strcpy(d, szTrkFile) ;
							A.szKnowntrk[u] = d ;
							A.iTrkIDs++ ;
						}

				  if ((htrack = OpenFile(szTrkPath, &of, OF_EXIST)) == HFILE_ERROR)
				  {
					  htrack = OpenFile(szTrkPath, &of, OF_CREATE) ;
					  _lclose(htrack) ;
				  }

				  ivrc(hWnd, &rctl[Aut], FALSE) ;

				  MeasureGrid(pMeasure) ;
				  MeasureTrackedBud(Tk) ;

				  if (!AllDone)
				   {
					  char note[100] ;
					   int response ;

					  sprintf(note,
                          "Some bud width measurements\n" \
                          "   could not be obtained.\n" \
                    "\n\n\nPlease confirm that the Tracks extend" \
                        "\nsufficiently on the bud's profiles.\n\n" \
                          "Do you wish to re-do the tracking?\n"
					) ;
					  msgbox = 1 ;	  
					  response  = MessageBox(hWndBud,
						                     note,
								            "MeasureTrackedBud()",
						                     MB_ICONEXCLAMATION|MB_YESNO) ;
					  msgbox = 0 ;

					  if (response == IDYES)
					  {
					   if (FreeTrackMemory(&Tk)) AllocTrackHyts(&Tk, hs) ;
				       autotracked = AUT = 0 ;
			           ivrc(hWnd,&rctl[Aut],FALSE) ;
				       autolftdone = ALF = 0 ;
					   ivrc(hWnd,&rctl[Alf],FALSE) ;
				       autorytdone = ART = 0 ;
					   ivrc(hWnd,&rctl[Art],FALSE) ;
					  }
				   }
			  }

			  break ;


		  case SET_HI_POLE:
		 
			 HIP = (HIP) ? btn_up : btn_down ; // toggle action
			 setpole = SETTOP =  HIP ;
			 //we may be showing the draghandles
			 dragstarted = 0 ;
			 if (setpole) 
			 {
				 if (setlevels)	 // turn off level setting
				 {
			  setlevels = LLV = btn_up ;
			  ivrc(hWnd,&rctl[Lev],FALSE) ;
				 }

				 if (scanning)	 // turn off scanning
					 SendMessage(hWnd,WM_COMMAND,TOGGLE_SCAN,0L) ;

			 if (TOPSET) // if the pole is already set..
			 {
			 // put the cursor on last-recorded pole position
				 image.x = pBudResults->BudTopPoleX ;
				 image.y = pBudResults->BudTopPoleY ;
				 ImgToCli(&client,&image) ;
			 }
			 else // top pole is not set 
			 {
				 if (PoleSettings) // this is not the first pole setting this session
				 {
			 // put the cursor on the most recently used pole position
				 image.x = MRUTopX ;
				 image.y = MRUTopY ;
				 ImgToCli(&client,&image) ;
				 }
				 else // this is the first pole setting this session
				 {
			 // and the pole has not been set already,
			 // so place cursor near top of image,
			 // i.e., centre the cursor 9/10 up image
			 // ready for proper placing.
				 client.x =     (rcimg.right + rcimg.left) / 2 ;
				 client.y = rcimg.bottom - 9 * (rcimg.bottom - rcimg.top) / 10 ;
				 CliToImg(&image, &client) ;
				 }
			 }

				 ClientToScreen(hWnd, &client) ;
				 SetCursorPos(client.x, client.y) ;

				 SetRect(&rcTpole,
					 client.x - 10,
					 client.y - 10,
					 client.x + 10,
					 client.y + 10
					 ) ;

				 MRTopX = image.x ;		// keep a record of the position
				 MRTopY = image.y ;		// of pole for possible restoration.
				 MRBotX = pBudResults->BudBotPoleX ;
				 MRBotY = pBudResults->BudBotPoleY ;
				 
			 // either way, say top pole not set, as we are
			 // in the middle of setting it!
			 if (HIP) TOPSET = reset ;
		     }
			 ivrc(hWnd,&rctl[Hip],FALSE) ;
			 UpdateWindow(hWnd) ;
			 Locked = JustLocked = previousline = reset ;
		 	 toArchive = set ;
			  break ;

		  case SET_LO_POLE:
		 
			 //if button down, release it, else press it
			 LOP = (LOP) ? btn_up : btn_down ;
			 //if button down, we're (re)setting the low pole
			 setpole = LOP ; SETTOP = !LOP ;
			 // we may be showing the drag handles
			 dragstarted = 0 ;
			 if (setpole) 
			 {
				 if (setlevels)	  // turn off level setting
				 {
			  setlevels = LLV = btn_up ;
			  ivrc(hWnd,&rctl[Lev],FALSE) ;
				 }

				 if (scanning)	  // turn off scanning
					 SendMessage(hWnd,WM_COMMAND,TOGGLE_SCAN,0L) ;

			if (BOTSET) // if the low pole is already set
			{
			 // put the cursor on last-recorded pole position
			 // ready for a possible move.
				 image.x = pBudResults->BudBotPoleX ;
				 image.y = pBudResults->BudBotPoleY ;
				 ImgToCli(&client,&image) ;
			}
			else // the low pole is not already set
			{
				 if (PoleSettings) // it is NOT the 1st low pole setting this session
				 {
			 // so put the cursor on last-used pole position this session
			 // ready for a possible move.
				 image.x = MRUBotX ;
				 image.y = MRUBotY ;
				 ImgToCli(&client,&image) ;
				 }
				 else // it IS the 1st low pole setting this session
				 {
			  // first setting: put at default position -
			  // i.e., centre cursor 1/10 up image,
			  // ready for proper placing.
				 client.x = (rcimg.right + rcimg.left) / 2 ;
				 client.y = rcimg.bottom - (rcimg.bottom - rcimg.top) / 10 ;
				 CliToImg(&image, &client) ;
				 }
			}
				 ClientToScreen(hWnd, &client) ;
				 SetCursorPos(client.x, client.y) ;

				 SetRect(&rcBpole,
					 client.x - 10,
					 client.y - 10,
					 client.x + 10,
					 client.y + 10
					 ) ;

				 MRBotX = image.x ;		// keep a record of the position
				 MRBotY = image.y ;		// of the pole for possible restoration.
				 MRTopX = pBudResults->BudTopPoleX ;
				 MRTopY = pBudResults->BudTopPoleY ;

			     if (LOP) BOTSET = reset ;
		     }
			 ivrc(hWnd,&rctl[Lop],FALSE) ;
			 UpdateWindow(hWnd) ;
			 Locked = JustLocked = previousline = reset ; 
		 	 toArchive = set ;
			  break ;

		  case LEVEL_UP:			  // Shift + up arrow key
			  if (scanning)
			  {
				 oldbutton = Levels - LevelSelect ;
				 LEV[oldbutton] = btn_up ; // cancel former selection
			  	 ivrc(hWnd,&rclv[oldbutton],FALSE) ;
				 LevelSelect += 1 ;		   // next level up
				 if ( LevelSelect > Levels ) LevelSelect = Levels ;
				 button = Levels - LevelSelect ;
				 LEV[button] = btn_down ;  // set button to selected
			     ivrc(hWnd,&rclv[button],FALSE) ;
			     UpdateWindow(hWnd) ;
				 // flag up that a level is selected
				 //(for cursor-trapping)
				 Locked = JustLocked = set ;
				 // give level in Bud window's title bar
				 strcpy(szBudWindowTit1,_strlwr(DropPath(szFile))) ;
				 sprintf(string,": locked on level %d of %d",
					             LevelSelect, Levels) ;
				 strcat(szBudWindowTit1,string) ;
				 SetWindowText(hWndBud,szBudWindowTit1) ;
			  }
			  break ;

		  case LEVEL_DN:			// Shift + down arrow key
			  if (scanning)
			  {
				 oldbutton = Levels - LevelSelect ;
				 LEV[oldbutton] = btn_up ; // cancel former selection
			  	 ivrc(hWnd,&rclv[oldbutton],FALSE) ;
				 LevelSelect -= 1 ;		   // next level down
				 if (LevelSelect < 1) LevelSelect = 1 ;
				 button = Levels - LevelSelect ;
				 LEV[button] = btn_down ;  // set button to selected
			     ivrc(hWnd,&rclv[button],FALSE) ;
			     UpdateWindow(hWnd) ;
				 // flag up that a level is selected
				 //(for cursor-trapping)
				 Locked = JustLocked = set ;
				 // give level in Bud window's title bar
				 strcpy(szBudWindowTit1,_strlwr(DropPath(szFile))) ;
				 sprintf(string,": locked on level %d of %d",
					             LevelSelect, Levels) ;
				 strcat(szBudWindowTit1,string) ;
				 SetWindowText(hWndBud,szBudWindowTit1) ;
			  }
			  break ;

		  case NUDGE_UP_FAST:
			  GetCursorPos(&curpt) ;
			  SetCursorPos((int)curpt.x, (int)curpt.y - Ynudge) ;
 			  break ;

		  case NUDGE_UP:
			  GetCursorPos(&curpt) ;
			  SetCursorPos((int)curpt.x, (int)curpt.y - 1) ;
 			  break ;

		  case NUDGE_DN_FAST:
			  GetCursorPos(&curpt) ;
			  SetCursorPos((int)curpt.x, (int)curpt.y + Ynudge) ;
  			  break ;

		  case NUDGE_DN:
			  GetCursorPos(&curpt) ;
			  SetCursorPos((int)curpt.x, (int)curpt.y + 1) ;
  			  break ;

		  case NUDGE_RIGHT_FAST:		 // Ctrl + right arrow key
  			  GetCursorPos(&curpt) ;
			  SetCursorPos((int)curpt.x + Xnudge, (int)curpt.y) ;
			  break ;

		  case NUDGE_RIGHT:			 // right arrow key
  			  GetCursorPos(&curpt) ;
			  SetCursorPos((int)curpt.x + 1, (int)curpt.y) ;
			  break ;

		  case NUDGE_LEFT_FAST:	     // Ctrl + left arrow key
 			  GetCursorPos(&curpt) ;
			  SetCursorPos((int)curpt.x - Xnudge, (int)curpt.y) ;
			  break ;

		  case NUDGE_LEFT:			 // left arrow key
 			  GetCursorPos(&curpt) ;
			  SetCursorPos((int)curpt.x - 1, (int)curpt.y) ;
			  break ;

		 // case TOGGLE_TIPS:		   // Ctrl T.  This jams things. Why?
		 //	  showtips ^= 1 ;
		 //	  break ;

		  case NEXT_INST:			// Alt + right arrow
			  break ;

		  case PREV_INST:			// Alt + left arrow
			  break ;

		  case RESIZE_IMAGE:
			  if (!noselect)
			  {
			  if (resized)	//check if to revert to original image
			  {
				  msgbox = 1 ;
				  UserSays = MessageBox(hWnd,
					  "ARE YOU SURE?\n\nThis will cancel all\nresults so far obtained.",
					  "Revert to Original Image.",
					   MB_ICONQUESTION|MB_YESNO
					  ) ;
				  msgbox = 0 ;
			  
				  if (UserSays == IDYES)
				  {
				  REZ = 0 ;
				  SendMessage(hWnd,WM_COMMAND,RESTORE_IMAGE,0L) ;
				  }
				  
			  }
			  else          // is not resized, and should be now
			  {
				  resizing = toArchive = 1 ;
				  REZ = 1 ;
				  ivrc(hWnd,&rctl[Rez],FALSE) ;
				  UpdateWindow(hWnd) ;
			  }
			  }
			  break ;

		  case UP_TRIAL_LAM:	   // Page up key
			  TrialLam += TLamInc ;
			  SendMessage(hWnd,WM_COMMAND,ON_DRAW_CHANGE,0L) ;
			  SendMessage(hWnd,WM_COMMAND,PRINT_COORDS,0L) ;
			  break ;

		  case DN_TRIAL_LAM:	   // Page down key
			  TrialLam -= TLamInc ;
			  if (TrialLam < TLamInc) TrialLam = TLamInc ;
			  SendMessage(hWnd,WM_COMMAND,ON_DRAW_CHANGE,0L) ;
			  SendMessage(hWnd,WM_COMMAND,PRINT_COORDS,0L) ;
			  break ;

		  case UP_TRIAL_RAD:	  // Home key
			  TrialRad += TRadInc ;
			  SendMessage(hWnd,WM_COMMAND,ON_DRAW_CHANGE,0L) ;
			  SendMessage(hWnd,WM_COMMAND,PRINT_COORDS,0L) ;
			  break ;

		  case DN_TRIAL_RAD:	  // Insert key
			  TrialRad -= TRadInc ;
			  if (TrialRad < TRadInc) TrialRad = TRadInc ;
			  SendMessage(hWnd,WM_COMMAND,ON_DRAW_CHANGE,0L) ;
			  SendMessage(hWnd,WM_COMMAND,PRINT_COORDS,0L) ;
			  break ;

		  case PRINT_COORDS:
			  if (CurInImg && !Locked)
		      {
			  switch (Units)
			  {
			  case IMPERIAL:
				  factor = (double)ws / DIBitsPerIn ;
				  break ;
			  case METRIC:
				  factor = (double)ws / DIBitsPerMm ;
				  break ;
			  case IMAGEUNITS:
			  default:
				  factor = 1.0 ;
				  break ;
			  }
// Clear print area first
			  ivrc(hWnd, &rcwipe, TRUE) ;
// Rescue other items
			  vrc(hWnd, &rcimg) ;
			  vrc(hWnd, &rccol) ;
// go wipe
			  UpdateWindow(hWnd) ;

// If we are setting a pole,
// print the interpole distance.

    if (setpole) 
	{
		M = pMeasure ;
		if (TOPSET & !BOTSET)
			D = sqrt(pow(M->iTopPole.x - (double)xm,2.0)
			       + pow(M->iTopPole.y - (double)ym,2.0));
		else
		if (!TOPSET & BOTSET)
			D = sqrt(pow(M->iBotPole.x - (double)xm,2.0)
			       + pow(M->iBotPole.y - (double)ym,2.0));
		else
			D = 0.0 ;

	if (showPC)	// If we are showing the trial path curve..
	   sprintf(pos,"Tr. Lam. %4.3f | Tr. Rad. %4.3f %s | IPD %4.3f %s",
	         TrialLam, 0.5 * TrialRad * factor, kind[Units],
			 D * factor, kind[Units] ) ;
	else // just show the inter-pole span.
	   sprintf(pos,"Pole Span %4.3f %s",
			 D * factor, kind[Units] ) ;
	}
	else // Give the general whereabouts of the cursor
		sprintf(pos,"(%3.3d,%3.3d) x: %4.3f %s, y: %4.3f %s",
	        xRGB, yRGB,
			xm * factor, kind[Units],
			ym * factor, kind[Units] ) ;

	
          hdc = GetDC( hWnd ) ;				  // get the DC
          oFnt = SelectObject( hdc, hfnt ) ;  // get the font into it
		    SetBkColor(hdc, RGB(0,     0, 0)) ;		// black background
          SetTextColor(hdc, RGB(255, 255, 0)) ;		// yellow text
		  GetTextExtentPoint32(hdc,			  // get the string dimensions
			                   pos,
							   strlen(pos),
							   &sz) ;

	      	// centre horizontally in window, if we can
		        xplace = (rcimg.left + rcimg.right)/2  - (int)sz.cx/2 ;
			// else keep it visible as much as possible---
				// try to keep clear of button
				if (xplace < 40) xplace = 44 ;
				// but not if spill would occur on right
				if (xplace > rcb.right - sz.cx)
					xplace = rcb.right - sz.cx ;
		    // print just below image
				yplace = rcimg.bottom + 4 ; // + (int)sz.cy ;

	      TextOut(hdc, xplace,
                       yplace,
                       pos,
                       strlen(pos)) ;

          SelectObject( hdc, oFnt ) ;		  // clean up
          ReleaseDC( hWnd, hdc) ;
			  }
			  break ;


		  case TOGGLE_PC:
			  showPC ^= 1 ;
			  SendMessage(hWnd,WM_COMMAND,ON_DRAW_CHANGE,0L) ;
			  break ;

		  case ON_DRAW_CHANGE:
		  if (setpole && CurInImg)
		  {
				  //rubber line if either pole is set but not if both
				  //are set or if neither is -- XOR, in short!.

				if ( TOPSET ^ BOTSET )
				{
					M = pMeasure ;
				 // if hi pole is set but lo pole is not
				if (TOPSET) //lo pole is not set
				 { 
				   p.x = M->iTopPole.x ;
				   p.y = M->iTopPole.y ;
				   ImgToCli(&pt1,&p) ;
				   xo = pt1.x ; 
				   yo = pt1.y ; 
				 } 

				// if lo pole is set but hi pole is not
				if (BOTSET)	//hi pole is not set
				 {
				   p.x = M->iBotPole.x ;
				   p.y = M->iBotPole.y ;
				   ImgToCli(&pt1,&p) ;
				   xo = pt1.x ;
				   yo = pt1.y ;
				 } 
				
				//draw rubber line from set pole
				//to current mouse position, and
				//if selected,the match PCurve too.

			if (previousline) // rub out the old
			{
				RubberLine(hWnd, oxo, oyo,  ox1, oy1) ;
				if (showPC)
				TrialPC(hWnd, oLam, oRad,
				              oxp, oyp, oxp1, oyp1, whitePen) ; 
			}
				RubberLine(hWnd, oxo = xo,  oyo = yo,	 // draw new
					             ox1 = Xms, oy1 = Yms) ;
				if (showPC){
				 Lam = (TOPSET) ? 1.0/TrialLam  : TrialLam  ;
				TrialPC(hWnd, oLam = Lam,   oRad  = TrialRad,
						      oxp  = p.x ,  oyp  = p.y,
						      oxp1 = xm,    oyp1 = ym,
							  whitePen) ;}

				previousline = 1 ;
			}
		  }

			  break ;


		  case ENTER_ACCEPT_MARK:   // Alt + Enter
		  case SPACE_ACCEPT_MARK:	// Alt + Space Bar
		 if (calibrating && !setpole && !scanning && !setlevels && CurInImg)
		 {
			 toArchive = 1 ;
			 if (SETCAL1) // The position of first mark is found
			 {
				    CAL1SET = set ;
				calibrating = reset ;
			           CAL1 = btn_up ;
					  //Units = IMAGEUNITS ;
				ivrc(hWnd, &rctl[Ca1], FALSE) ;
				ivrc(hWnd, &rcimg, TRUE) ;
				UpdateWindow(hWnd) ;
			 }
			 else		// The position of the second mark is found
			 {
				    CAL2SET = set ;
				calibrating = reset ;
			           CAL2 = btn_up ;
					 // Units = IMAGEUNITS ;
				ivrc(hWnd, &rctl[Ca2], FALSE) ;
				ivrc(hWnd, &rcimg, TRUE) ;
				UpdateWindow(hWnd) ;
			 }
			 
			 if (CAL1SET && CAL2SET ) // process the calibration
			 {
				 Calib = DialogBox(
					 hInst,
					 MAKEINTRESOURCE(IDD_CALIBRATION),
					 hWnd,
					 CalibDlgProc
					 ) ;

				 if (Calib == IDOK)
				 {
					 InterCalMarkDIBits = sqrt(
						 pow(xMark2 - xMark1, 2.0) +
						 pow(yMark2 - yMark1, 2.0)
						            ) ;
				   switch (Units)
				   {
				   case METRIC:
				   DIBitsPerMm = InterCalMarkDIBits/CalSize ;
				   DIBitsPerIn = DIBitsPerMm / 25.4 ;
				   DIBitsPerIm = (double) ws ;
					   break ;

				   case IMPERIAL:
				   DIBitsPerIn = InterCalMarkDIBits/CalSize ;
				   DIBitsPerMm = DIBitsPerIn * 25.4 ;
				   DIBitsPerIm = (double) ws ;
					   break ;

				   case IMAGEUNITS:
				   DIBitsPerIm = (double) ws ;
				   DIBitsPerIn = 0.0 ;
				   DIBitsPerMm = 0.0 ;
					   break ;
				   }
				   calibrating = reset ;
				    calibrated =   set ;
				   ivrc(hWndRslt, NULL, FALSE) ;
				   UpdateWindow(hWndRslt) ;
				   ivrc(hWndBud, NULL, FALSE) ;
				   UpdateWindow(hWndBud) ;
				 }
			 }
		 }
			  break ;

		  case ENTER_ACCEPT_POLE:  // Ctrl + Enter
		  case SPACE_ACCEPT_POLE:  // Ctrl + Space Bar
		 if ( setpole     && 
			 !setlevels   && 
			 !scanning    && 
			 !calibrating && 
			  CurInImg )    
		 {
			 M = pMeasure ;
			 B = pBudResults ;
			 toArchive = 1 ;

			 if (SETTOP)			// it is the top pole
			 {
		       M->iTopPole.x = pBudResults->BudTopPoleX = MRUTopX = xm ; 
		       M->iTopPole.y = pBudResults->BudTopPoleY = MRUTopY = ym ;

				 SetRect(&rcTpole,	// drag rectangle
					 Xms - 10,
					 Yms - 10,
					 Xms + 10,
					 Yms + 10
					 ) ;

			   RecordDimensions() ;
				 TOPSET = set ;		// top pole is set
				    HIP = btn_up ;
				setpole = reset ;  // cancel pole setting
				 ivrc(hWnd,&rctl[Hip],FALSE) ;
			 }
			 else				    // it is the bottom pole
			 {
		       M->iBotPole.x = pBudResults->BudBotPoleX = MRUBotX = xm ; 
			   M->iBotPole.y = pBudResults->BudBotPoleY = MRUBotY = ym ;

				 SetRect(&rcBpole,	// drag rectangle
					 Xms - 10,
					 Yms - 10,
					 Xms + 10,
					 Yms + 10
					 ) ;

			   RecordDimensions() ;
				 BOTSET = set ;		// bottom pole is set
				    LOP = btn_up ;
				setpole = reset ;       // cancel pole setting
				 ivrc(hWnd,&rctl[Lop],FALSE) ;
			 }
			 // turn off the cursor rotation
			 KillTimer(hWndBud,RotCurTim) ;
			 currotate = 0 ;
			 // turn off timer if both poles set
			 // and increment the number of
			 // pole settings done this session
			 if (TOPSET && BOTSET)
			 {
				 KillTimer(hWnd, Blink) ;
				 PoleSettings++ ;
			 }
			 
			 ivrc(hWnd,&rcb,FALSE) ;
			 UpdateWindow(hWnd) ;

			 if (autotracked)
			 {
remeasure:		toArchive = 1 ;
				MeasureGrid(pMeasure) ;
		        MeasureTrackedBud(Tk) ;
				  if (!AllDone)
				   {
					  char note[100] ;
					   int reply ;
					 //int reply1 ;

					  sprintf(note,
                          "Some measurements could not be obtained.\n" \
                    "\n\n\nDo you wish to cancel these Pole-settings\n" \
                          "and restore the Poles to their former positions?") ;

					  msgbox = 1 ;	  
					  reply = MessageBox(hWndBud,
						         note,
								"MeasureTrackedBud()",
						         MB_ICONQUESTION|MB_YESNO) ;
					  msgbox = 0 ;

					  switch (reply)
					  {
					  case IDYES:  // Just re-establish the former pole positions, then re-measure.
		                 M->iTopPole.x = pBudResults->BudTopPoleX = MRTopX ; 
		                 M->iTopPole.y = pBudResults->BudTopPoleY = MRTopY ;
		                 M->iBotPole.x = pBudResults->BudBotPoleX = MRBotX ; 
			             M->iBotPole.y = pBudResults->BudBotPoleY = MRBotY ;
			             RecordDimensions() ;
						 goto remeasure ;
						  break ;

					  case IDNO:   // Offer the option of re-doing the tracking instead.
				/***
					  msgbox = 1 ;	  
					  reply1 = MessageBox(hWndBud,
						        "Do you wish to Cancel Tracking for Re-doing?",
								"Pole Positions are Confirmed.",
						         MB_ICONEXCLAMATION|MB_YESNO) ;
					  msgbox = 0 ;

					  if (reply1 == IDYES)
					  {
					   if (FreeTrackMemory(&Tk)) AllocTrackHyts(&Tk, hs) ;
				       autotracked = AUT = 0 ;
			           ivrc(hWnd,&rctl[Aut],FALSE) ;
				       autolftdone = ALF = 0 ;
					   ivrc(hWnd,&rctl[Alf],FALSE) ;
				       autorytdone = ART = 0 ;
					   ivrc(hWnd,&rctl[Art],FALSE) ;
					  }
				***/
						  break ;
					  }
				   }

				 if (shownullgraph)
					 ivrc(hWndNPGraf, NULL, TRUE) ;
			 }
			 else
			{
			 // tell measurement department
			 toArchive = 1 ;
			 ResetMeasure(hWnd, LEV, EdgeDone) ;
			 RecordDimensions() ;
			 RecordLambdas() ;
			 SendMessage(hWndRslt, WM_RESET, 0, 0L) ;
			 ivrc(hWndRslt,&rcrslt,FALSE) ;
			 UpdateWindow(hWndRslt) ;
			}

		 }
			  break ;

		  case ENTER_ACCEPT_MEASURE: // either of the Enter keys
		  case SPACE_ACCEPT_MEASURE: // or the Space bar, or left click.
		 if (scanning & Locked & stored & CurInImg)
			 {
				if (IsWindow(hWndZoom)) ShowWindow(hWndZoom, SW_HIDE) ;
				     M = pMeasure ;
					 B = pBudResults ;
			         L = LevelSelect ;
				button = Levels - L ;
				    x2 = M->iAxisCuts[L].x ;
					y2 = M->iAxisCuts[L].y ;

					toArchive = 1 ;

	// flag whether mouse left or right of current bud axis
	      onLeft = (xm <= M->iAxisCuts[L].x) ? set : reset ;

			   if (onLeft)
			   {
				   M->iLeftCut[L].x = x1 = xm ;
			       M->iLeftCut[L].y = y1 = ym ;
				   M->iLeftRad[L] = sqrt(pow(x2-x1,2.0)+pow(y2-y1,2.0)) ;

				   Construct( L, LEFT ) ;
				   LEdgeOrg[L] = EYEBALLED ;
			   }
			   else
			   {
				   M->iRightCut[L].x = x1 = xm ;
			       M->iRightCut[L].y = y1 = ym ;
				   M->iRightRad[L] = sqrt(pow(x2-x1,2.0)+pow(y2-y1,2.0)) ;

				   Construct( L, RIGHT ) ;
				   REdgeOrg[L] = EYEBALLED ;
			   }

				   ivrc(hWnd,&rclv[button],FALSE) ;
				   UpdateWindow(hWnd) ;

				   // check for all levels measured: first assume they are,
				   // then if one found which isn't, reset AllDone flag.

				   for (i = 1, AllDone = 1; i <= Levels ; i++)
					   if (EdgeDone[i] != BOTH) AllDone = 0 ;

				   // if they are, go ahead with Lambda calculations

				  if (AllDone)
				  {
        		   Lambda(LEFT) ;
				   Lambda(RIGHT) ;
				   Lambda(BOTH) ;
				   RecordLambdas() ;
				   
                   TrialLam = PRJ?
					   pBudResults->DiamProjLambda : pBudResults->DiamRegrLambda;
				   TrialRad = 0.5 * pMeasure->iDiameter[(Levels+1)/2] ;
				   if (autoRes)
				   {
				   if (Locked)	   //lift button
					   SendMessage(hWnd,WM_COMMAND,RELEASE_LOCK,0L) ;
				   if (scanning)   //turn off scanning
					   SendMessage(hWnd,WM_COMMAND,TOGGLE_SCAN,0L) ;
				   if (graphing)   //turn off line scans if on
					   SendMessage(hWnd,WM_COMMAND,TOGGLE_GRAPHS,0L) ;
				   }
				   if (autoMax)
				   ShowWindow(hWndRslt,SW_MAXIMIZE) ;
				   if (commentary)
				   PlaySound(sBite[9], NULL, SND_ASYNC) ;
				  }
				   toArchive = 1 ;
				   SomeDone = set ;
				   RecordDimensions() ;
 				   ivrc(hWndRslt,&rcrslt,TRUE) ;
				   UpdateWindow(hWndRslt) ;

 			 }
        return 0 ;
			  break ;

		  case RELEASE_LOCK:
		 if (scanning & Locked)
		 {   
			 button = Levels - LevelSelect ;
			 Locked = JustLocked = reset ;
			 LEV[button] = btn_up ;
			 ivrc(hWnd,&rclv[button],FALSE) ;
			 LevelSelect = reset ;
				 strcpy(szBudWindowTit1,_strlwr(DropPath(szFile))) ;
				 sprintf(string,": Free cursor") ;
				 strcat(szBudWindowTit1,string) ;
				 SetWindowText(hWndBud,szBudWindowTit1) ;
		 }
			  break ;

		  case WIDE_CURSOR:	 // toggle cursor width
			  if (scanning)
			  {
				  wide = wide ? 0 : 1 ;
				  while (ShowCursor(TRUE)<0) ; // make sure it shows
			  }

			  break ;

          default: break ;

         }
        break ;
     
	 case WM_MOUSEMOVE:
        
            Xms = pt.x = LOWORD(lParam) ;   // get mouse client coords
			Yms = pt.y = HIWORD(lParam) ;

	  if (gotimage) 
	  {
		    
		  if (showtips)
		  {
			GetCursorPos(&cpt) ; // get the screen co-ords of the mouse
			ScreenToClient(hWnd, &cpt) ;
 		    GetTip( hWnd, Lop, Ca2, cpt ) ;
			GetTip( hWnd, Aut, Prm, cpt ) ;
			GetTip( hWnd, Lsa, Lsb, cpt ) ;
			if (sounds)
			{
       		GetVoc( hWnd, Lop, Ca2, cpt ) ;
       		GetVoc( hWnd, Aut, Prm, cpt ) ;
			}
		  }

// Poll for the mouse in a level button
		  {
			 static x, ox, y, oy ;
			 static rx, rox, ry, roy ;
			 static Icon1Drawn, Icon2Drawn, wuzheer ;

		  if (PtInRect(&rccol, pt))
		  {
		  for (i = 1 ; i <= Levels ; i++)    // OK, which one is it in?
		  {
		    if (PtInRect(&rclv[Levels - i], pt)) // it's this one
			{
				if (wuzheer != i) // OK, then if this is not the same old button...
				{
			     if (shownullgraph)	// is Null Profile graph showing?
			    {
				// If nullgraph is showing, these rectangles,
				// centred on the data points, are defined.
				// Get the centre corresponding to the selected button.
				    x = rcNull[i].left + 2 ;
				    y = rcNull[i].top  + 2 ;
				  if (hPatch != NULL && Icon1Drawn)				   // if grabbed patch exists
				  {
					  hPatch = PutPatch(hWndNPGraf, hPatch, 32, 32, ox, oy) ; // replace it, so wiping the icon
					  Icon1Drawn = 0 ;
				  }
				  hPatch = GrabPatch(hWndNPGraf, 32, 32, x + 3, y + 3) ; // grab a new patch
				   ox = x + 3 ; oy = y + 3 ;				       // record place for restoration
				   hdc1 = GetDC(hWndNPGraf) ;
				   DrawIcon(hdc1, x + 3, y + 3, icoPtr) ;		   // draw the arrow-icon on top
				   Icon1Drawn = 1 ;
				   ReleaseDC(hWndNPGraf, hdc1) ;
			    } // end if (shownullgraph)

				if (EdgeDone[i] == BOTH)   // the Results window nearly always shows
				{
					rx = rcmidpt[i].left + 4 ;
					ry = rcmidpt[i].top  + 4 ;
				  if (hPatch1 != NULL && Icon2Drawn)
				  {
					  hPatch1 = PutPatch(hWndRslt, hPatch1, 32, 32, rox, roy) ;
					  Icon2Drawn = 0 ;
				  }
				  hPatch1 = GrabPatch(hWndRslt, 32, 32, rx + 3, ry + 3) ;
				   rox = rx + 3 ; roy = ry + 3 ;				   // record place for restoration
				   hrdc = GetDC(hWndRslt) ;
				   DrawIcon(hrdc, rx + 3, ry + 3, icoPtr) ;	       // draw the arrow-icon
				   Icon2Drawn = 1 ;
				   ReleaseDC(hWndRslt, hrdc) ;
				}
			  }
			  wuzheer = i ; // The mouse is still MOVING in this button
			  }
		   } // try for another button
		  } 
		    else	// mouse is not in button column, replace patch(es) if they exist
		    {
				wuzheer = 0 ; // signal that mouse was not in any button

					if (shownullgraph && hPatch && Icon1Drawn)
					{
						hPatch = PutPatch(hWndNPGraf, hPatch,  32, 32, ox,  oy ) ;
						Icon1Drawn = 0 ;
					}

					if (hPatch1 && Icon2Drawn)
					{
						hPatch1 = PutPatch(hWndRslt, hPatch1, 32, 32, rox, roy) ;
						Icon2Drawn = 0 ;
					}
		    }
	}

/**********************************************************************/

	  // is the mouse in the image? 
      CurInImg = (PtInRect(&rcimg,pt) == TRUE) ? 1 : 0 ;

	  if (CurInImg)
	  {
		   if (!wuzin) wuzin = 1 ;		// just arrived
		   // else still in
	  }
	  else // not in
	  {
		  if (wuzin)
		  {
			  wuzin = 0 ;				// just left, wipe the print area
			  ivrc(hWnd, &rcwipe, TRUE) ;
			// Rescue other items
			  vrc(hWnd, &rcimg) ;
			  vrc(hWnd, &rccol) ;
			// go wipe
			  UpdateWindow(hWnd) ;
		  }
		  // else still out
	  }

	  // if the cursor is not in the image,
	  // use the standard arrow cursor
      if (!CurInImg)  oldCursor = SetCursor(LoadCursor(NULL,IDC_ARROW)) ;


	  // experimental
	  CurAtPole = (PtInRect(&rcTpole,pt) || PtInRect(&rcBpole,pt)) ? 1 : 0 ;
/*
	  {
		  POINT p ;

	   if (dragtop && (wParam & MK_LBUTTON)) // we are dragging the top pole 
	   {
		  SetRect(&rcTpole,
			      pt.x + dx,  // left
				  pt.y + dy,  // top
				  pt.x + dx +   , // right
				  pt.y + dx 

				
	   }
	   if (dragbot && (wParam & MK_LBUTTON)) // we are dragging the bottom pole
	   {
	   }
	  }
*/
	  if (CurInImg)
	  {
		  if (!stored && scanning && !batching) GetLineStorage() ;

	   // Get mouse position in image units
		      CliToImg(&p, &pt) ;
		        xm = p.x ; 
                ym = p.y ;

	   // Find the cursor's pixel in the Buffer Inset.
			  CliToInset(&pd, &pt) ;
			  xINS = pd.x ;
			  yINS = pd.y ;

			  // Debuggery:

	     if (xINS < 0 || xINS > ws || yINS < 0 || yINS > hs)
			{
				char st[100] ;
				sprintf(st,"xINS: %d yINS: %d", xINS, yINS) ;
				MessageBox(NULL, st, "Image Inset: Indexing Error!",
					       MB_ICONEXCLAMATION|MB_OK) ;
			}

	   // Find the cursor's pixel in the RGB buffer.
			  CliToBuff(&pd, &pt) ;
			  xRGB = pd.x ;
			  yRGB = pd.y ;

			  // Debuggery:

	     if (xRGB < 0 || xRGB > (int)dibwid || yRGB < 0 || yRGB > (int)dibhyt)
			{
				char st[100] ;
				sprintf(st,"xRGB: %d yRGB: %d", xRGB, yRGB) ;
				MessageBox(NULL, st, "RGB Buffer: Indexing Error!",
					       MB_ICONEXCLAMATION|MB_OK) ;
			}
	  }

	  // If we are in scan mode, show the mouse position
	  // on the results image.

	  if (
		  CurInImg  &&
		  scanning  &&
		  !graphing &&
		 !(wParam & MK_LBUTTON)
		 )
      {

		  // Draw cross in results image 

       xr = MulDiv(Xms - rcimg.left, rimwid, bimwid) + rcresimg.left ;
       yr = MulDiv(Yms - rcimg.top,  rimhyt, bimhyt) + rcresimg.top ;

	      if ( wasin ) // is still in: draw old to erase it
		  {
             DrawX(hWndRslt, oxr, oyr, oarm, whitePen) ;
		  }
		  else         // just arrived
		  wasin = 1 ;  // record arrival
		               // Draw new, record as old.
	         DrawX(hWndRslt, oxr = xr, oyr = yr, oarm = arm, whitePen) ;
	  }
	  else  // is out
	  {
		  if (wasin) // just left
		  {
			  wasin = 0 ; // record departure.
			  // draw old to erase it
             DrawX(hWndRslt, oxr, oyr, arm, whitePen) ;
		  }
	  }

	// If we are not scanning, or setting anything, but the cursor
	// is in the current image, allow image resizing (if it is not
	// already resized), or the definition of a search region,
	// dragging with the left button

		  if (
			   CurInImg   &&
			  (resizing   ||
			   setsearch) && 
			  !scanning   &&
			  !setpole    &&
			  !setlevels  &&
			  !resized
			 )
		  {
			if (wParam & MK_LBUTTON)   // Left Button down
			{
			 KillTimer(hWnd,IDT_BTIMER) ; // it seems to interfere
			 hdc = GetDC(hWnd) ;
			 whitePen = SelectObject(hdc,whitePen) ;
			 SetROP2(hdc,R2_XORPEN) ;
			 if (prev == TRUE)
			 {
				 MoveToEx(hdc,ptstart.x,ptstart.y,(LPPOINT)NULL) ;
				   LineTo(hdc,ptprevend.x,ptstart.y) ;
				   LineTo(hdc,ptprevend.x,ptprevend.y) ;
				   LineTo(hdc,ptstart.x,ptprevend.y) ;
				   LineTo(hdc,ptstart.x,ptstart.y) ;
			 }

			 ptnow.x = Xms ;
			 ptnow.y = Yms ;

			 MoveToEx(hdc, ptstart.x, ptstart.y,(LPPOINT)NULL) ;
			 LineTo(hdc,ptnow.x,ptstart.y) ;
			 LineTo(hdc,ptnow.x,ptnow.y) ;
			 LineTo(hdc,ptstart.x,ptnow.y) ;
			 LineTo(hdc,ptstart.x,ptstart.y) ;
			 prev = TRUE ;
			 ptprevend = ptnow ;
			 whitePen = SelectObject(hdc,whitePen) ;
			 ReleaseDC(hWnd,hdc) ;
			}
		  }

		  if (CurInImg) // if mouse is in the image
		  {
/************************* Cursor management *********************/
	     	  
			  if (setpole) // if we are setting a pole
			  {
				if (!currotate)
				{
				RotCurTim = SetTimer(hWndBud, IDT_RTIMER, tRotCur, NULL) ;
				currotate = 1 ;
				}

			  }
			  else   // use one of the 'Target' cursors
			  {
				  /***  This is now in ENTER_ACCEPT_POLE to stop it immediately,
				        that is, without waiting for a mouse move

				  if (currotate) // if we have just been pole placing
				  {				 // kill the rotating cursor's timer
				  KillTimer(hWndBud,RotCurTim) ;
				  currotate = 0 ;
				  }
				  ***/

				  if (CurAtPole && !autodolft && !autodoryt)
				  {
			           oldCursor = SetCursor(LoadCursor(NULL,IDC_ARROW)) ;
				  }
				  else
				  {
			    if (Locked) // we are measuring, use "Lock" cursor
				{
				  if (!ISONPEAK)
				   {
					if (!wide)	     // is not the opened cursor
				        oldCursor = SetCursor(hTargetLock) ;//only locked.
					    else		 // is the opened, locked cursor
					    oldCursor = SetCursor(hTargetLockW) ;
				   }
				   else 
				   //is locked, scanning and on a possible "edge".
					    oldCursor = SetCursor(hDpeak) ; // a "hit".
			    }
				else
				// we are either scanning,
				// or tracking. 	  
				{
					if (!autodolft && !autodoryt) 
					// we are just scanning, use plain target cursor
					{
					 if (!ISONPEAK)
					 {
					  if (!wide)
				        oldCursor = SetCursor(hTarget) ; // normal cursor
					  else
					    oldCursor = SetCursor(hTargetW) ; // opened cursor
					 }
					 else
						 oldCursor = SetCursor(hDpeak) ; // a "hit".
					}
				   else  // we are tracking a profile
				   {
			        if (autodolft) // we are tracking the left profile 
			        {
				      oldCursor = SetCursor(hTracklftCur) ; 
			        }
					if (autodoryt) // we are tracking the right profile
			        {
				      oldCursor = SetCursor(hTrackrytCur) ; 
			        }
				   }
				}
			   }
			  }
		  }
		  else   // mouse is outside image, use standard arrow cursor
		  {
			  if (currotate) // if we are pole setting, kill rotation timer
			  { KillTimer(hWndBud,RotCurTim) ; currotate = 0 ;}
			  oldCursor = SetCursor(LoadCursor(NULL,IDC_ARROW)) ;
		  }
/******************* End Cursor Management *******************************/


		  // If the cursor is in the image, and we are not
		  // locked on a level or autotracking, print mouse coords.

		  if (CurInImg && 
			  !Locked &&
			  !(wParam & MK_LBUTTON) &&
			  !(wParam & MK_RBUTTON))
         {
			  SendMessage(hWnd,WM_COMMAND,PRINT_COORDS,0L) ;
	     }

 /****************** Measurement ******************************/

	// If we are not setting anything, but are scanning,
	// then if a measure level is selected (Locked),
	// constrain cursor to move in that level.

          if (scanning && CurInImg && stored && !setlevels && !setpole)
          {
		    if (Locked) // Constrain cursor to selected level 
		    {			//(click outside buttons/image or press
				        // ESC key to cancel.)

			       L = LevelSelect ;

	// image-relative line parameters for the level
			   grad  = M->iLevGradIcepts[L].x ;
			   icept = M->iLevGradIcepts[L].y ;

	// get current image-relative mouse X into the DPOINT
			    p2.x = xm ; //p.x == xm 

	// calculate corresponding Y for the level, place in DPOINT
			    p2.y = xm * grad + icept ;	 //p.x == xm
				
	// convert to client-relative, result in POINT
               ImgToCli(&pt2, &p2) ;
	
	// then to screen-relative, for SetCursorPos()
			   ClientToScreen(hWnd, &pt2) ;

	// place the cursor.  Ah. This must generate a WM_MOUSEMOVE msg.,
	// whether or not the mouse moves, so sustaining the loop, once
	// started. That has to be it! 
			   SetCursorPos(pt2.x, pt2.y) ;

			} // if (Locked)


	if (zoompatch && Locked && (Xms != oXms || Yms != oYms))
	{
	// magnify an image  region around the cursor
	// and show it above the cursor

// use odd numbers to suit integer division
		  zw =  zh = 15 ;	// centre of patch in patch coords
		 zwz = zhz = 61 ;	// 61 x 61 pixel patch
		 zdx = zdy = 55 ;	// 55 pixels up screen

		GetCursorPos( &pz ) ;			// where's the cursor?
		if (IsWindow(hWndZoom))			// get rid of any existing patch window 
			DestroyWindow(hWndZoom) ;

	 hWndZoom = CreateWindow			// make new pop up patch window
		 (
		"Overlay",
		 "",
		 WS_POPUP | WS_BORDER,
		 pz.x - zwz/2,              // x of top left of patch, in screen co-ordinates!!!
		 pz.y - zdy - zhz/2,
		 zwz,
		 zhz,
		 NULL,
		 NULL,
		 hInst,
	     NULL
		 );

	ShowWindow(hWndZoom, SW_SHOWNOACTIVATE) ;	// show the patch area

		hzDC = GetDC(hWndZoom) ;				// Get its DC
	 hzmemdc = CreateCompatibleDC( hzDC ) ;		// and a memory DC compatible with it

		hzBm = GetZoomPatch						// Get the patch
				(
					hWnd,
					Xms, Yms,
					zw, zh
				) ;

		ozBm = SelectObject(hzmemdc, hzBm) ;// Select the Zoompatch into the mem DC

	 StretchBlt								// Stretch the patch into the pop-up
		 (
		   hzDC,	// dest
		   0, 0, zwz, zhz,
		   hzmemdc,	// src
		   0, 0, zw, zh,
		   SRCCOPY
		 ) ;

	 oPen = SelectObject(hzDC, whitePen) ;	// Draw the Cross hair
	 MoveToEx(hzDC, zwz/2,   0,   NULL) ;
	   LineTo(hzDC, zwz/2, zhz  ) ;
	 MoveToEx(hzDC,   0,   zhz/2, NULL) ;
	   LineTo(hzDC, zwz,   zhz/2) ;
	   SelectObject(hzDC, oPen) ;
				 hzBm = SelectObject(hzmemdc, ozBm) ;	// Clean up
				 DeleteObject(hzBm) ;
				 DeleteDC(hzmemdc) ;
				 ReleaseDC(hWndZoom, hzDC) ;
		} // if (zoompatch etc.)


    // do scan "off-screen" in the RGB buffer 	  
			ScanRGBLine(
				        (BYTE *)pRGB,
						(UINT32)dibwid,
						(UINT32)yRGB,
						scancolour
						) ;               
	 if (graphing)
	 {
	// change scan display only on a change of mouse position
		   if (Xms != oXms || Yms != oYms)
           SendMessage(hWndScan,WM_COMMAND,IDM_SCAN,0L ) ;
	 }

	// if we are mouse-tracking a profile
	 if 
	(
	 autotrack && 
	!Locked    &&
	!resizing  &&
	!setsearch &&
	((wParam & MK_LBUTTON) || (wParam & MK_RBUTTON))
	)
	 {
		 if (Yms != oYms) // if we have had a y change
		 {
		 // Attempt to fill in intermediate points.
		 // Start at the first line after the old 
		 // line in the indicated sense.
		   Range = Yms - oYms ;
		   jumpmouse = 0 ;        // stop using the timer

		   for ( g = 1 ; g <= abs(Range) ; g++)
		   {
			   POINT Bf, Bd, Sd ;

			   if (Range > 0)
			  Yms = oYms + g ;
			   else
			  Yms = oYms - g ;
		  
		   // place the mouse cursor
			  client.x = Xms ;
			  client.y = Yms ;

			  CliToBuff(&Bf, &client) ;
			  yRGB = Bf.y ;
			  xRGB = Bf.x ;

			  ClientToScreen(hWnd,&client) ;
			  SetCursorPos(client.x, client.y) ;

			  ScanRGBLine(
				        (BYTE *)pRGB,
						(UINT32)dibwid,
						(UINT32)yRGB,
						scancolour
						) ;   

		   	  Ep = TrackRGBProfile(0, seekspan) ; // Ep is in client co-ords

		// let the indices be reckoned from the BOTTOM of the image.

		// if the captured end point (CEP) is valid
		if (Ep >= 0)
		{
			POINT Ss, Bb ;

			Sd.x = Ep ;  // in screen pix and includes the left client margin
			Sd.y = Yms ; // in screen pix from top of client
			CliToInset(&Bd, &Sd) ;   
			 BEp = Bd.x ;	   // in buffer pix and has no left buffer margin 
			Bidx = hs - Bd.y ; // height in buffer pix from bottom of buffer inset

			// Debuggery:

			if (Bidx < 0 || Bidx > hs)
			{
				char st[100] ;
				sprintf(st,"The RGB Buffer Index is %d", Bidx) ;
				MessageBox(NULL, st, "Track Indexing Error!", MB_ICONEXCLAMATION|MB_OK) ;
			}

		  if (autodolft) // we are doing the left profile
		  {
			// In Buffer
			Tk.Beplft[Bidx] = BEp ; 
			if (Bidx > Tk.Blfthiidx) Tk.Blfthiidx = Bidx ; // establish index of highest up
			if (Bidx < Tk.Blftloidx) Tk.Blftloidx = Bidx ; // establish index of lowest down
		  }

		  if (autodoryt) // we are doing the right profile
		  {
			// In Buffer
			Tk.Bepryt[Bidx] = BEp ; 
			if (Bidx > Tk.Brythiidx) Tk.Brythiidx = Bidx ; // establish index of highest up
			if (Bidx < Tk.Brytloidx) Tk.Brytloidx = Bidx ; // establish index of lowest down
		  }

			// go show the CEP temporarily on the results window.
		  
			 xrs = MulDiv(Ep - rcimg.left, rimwid, bimwid) + rcresimg.left ;
			 yrs = MulDiv(Yms - rcimg.top, rimhyt, bimhyt) + rcresimg.top  ;
			 {
				 HDC hDC ;
			 hDC = GetDC(hWndRslt) ;
			 SetPixel(hDC, xrs, yrs, RGB(255,255,255)) ;
			 ReleaseDC(hWndRslt, hDC) ;
			 }
		  
			 // Show on bud window. As a test, fetch from RGB buffer.
			 if (autodolft)
			 Bb.x = Tk.Beplft[Bidx] ;
			 else
			 Bb.x = Tk.Bepryt[Bidx] ;

			 Bb.y = hs - Bidx ;
			 InsetToCli(&Ss, &Bb) ;

			 {
				 HDC hDC ;
				hDC = GetDC(hWndBud) ;
				SetPixel(hDC, Ss.x, Ss.y, RGB(255,255,255)) ;
				ReleaseDC(hWndBud, hDC) ;
			 }

		 }
		   else // Profile is lost.
			    // Stop self-tracking.
		   {
			       KillTimer(hWnd, IDT_SELFTRKTIMER) ;
			   if (commentary)
				   PlaySound("proflost.wav", NULL, SND_ASYNC) ;
			   if (sounds && !commentary)
		           MessageBeep(MB_OK) ;
		   }
				// Adjust position and/or parameters then
				// re-press right mouse button to resume.
		}
		   jumpmouse = 1 ;	// resume timer use
	   }
	 } // end of mouse tracking
   }

     if (!CurInImg && IsWindow(hWndZoom)) ShowWindow(hWndZoom, SW_HIDE) ;

/**************** End of Measurement section **************************/

	// if we have autotracked and are setting a pole
	 if ( setpole && !scanning && CurInImg && autotracked )
	 {

		 if (Yms != oYms || Xms != oXms)
		 {
			 if (hWndInfo[NUMCONTROLS])
			 {
	         DestroyWindow(hWndInfo[NUMCONTROLS]) ;
			 hWndInfo[NUMCONTROLS] = NULL ;
			 }
			 UpdateWindow(hWnd) ;

			 if (SETTOP)
		     {
				 pMeasure->iTopPole.x = xm ;
				 pMeasure->iTopPole.y = ym ;
		     }
			 else // is SETBOT
			 {
				 pMeasure->iBotPole.x = xm ;
				 pMeasure->iBotPole.y = ym ;
			 }

			 MeasureGrid(pMeasure) ;
			 MeasureTrackedBud(Tk) ;

				  if (!AllDone) // warn about lost measurements
				   {
					   char note[100] ;
					  POINT p ;
					  p.x = Xms ;
					  p.y = Yms ;
					  ClientToScreen(hWnd, &p) ;
					  sprintf(note,
                          "    WARNING.    \n" \
                          " Measurement(s) Lost. "
						     ) ;
					  MakeOverlay(NUMCONTROLS, p.x + 40, p.y - 8, note) ;
				   }

			 if (shownullgraph)
			 ivrc(hWndNPGraf, NULL, TRUE) ;
			 toArchive = 1 ;
		 }
	 }

    // If we are setting a pole...

		  if (CurInImg && setpole)
		  {

			 if (ShowDragHandles)
			 {
			 static RECT rc1, rc2 ;
			 SetDragHandles(setpole) ;

			 if (!dragstarted)
			 {
			  dragstarted = 1 ;
			  goto Draw	;
			 }

			 ivrc(hWnd, &rc1, FALSE) ; // Invalidate handle rectangles
			 ivrc(hWnd, &rc2, FALSE) ;
			 UpdateWindow(hWnd) ;				 // Restore original patches of image

Draw:		 DrawDragHandles(hWnd) ;			 // put handles on top

			 CopyRect(&rc1, &rcTPico) ;			 // retain rectangles for next update
			 CopyRect(&rc2, &rcBPico) ;
			 }

				SendMessage(hWnd,WM_COMMAND,ON_DRAW_CHANGE,0L) ;
		  }

	// store current cursor position as old for next
		   oYms = Yms ;
		   oXms = Xms ;
		    oxm = xm ;
		    oym = ym ;
   }
        break ;

        case WM_RBUTTONDBLCLK:
			break ;


        case WM_RBUTTONDOWN:
			if (autotrack && !autotracked && CurInImg)
			SetTimer(hWnd, IDT_SELFTRKTIMER, SelfTrkRate, NULL) ;
		break ;
		
		case WM_RBUTTONUP:
			if (autotrack) // otherwise unconditional kill
			KillTimer(hWnd, IDT_SELFTRKTIMER) ;

		// toggle zoompatch
			if (scanning && Locked && CurInImg)
			{
			zoompatch ^= 1 ;
			if (!zoompatch && IsWindow(hWndZoom))
				ShowWindow(hWndZoom, SW_HIDE) ;
			else
				ShowWindow(hWndZoom, SW_SHOWNOACTIVATE) ;
			}
			
		// Select levels for exclusion from or re-inclusion in
		// the Lambda calculation.

		 if (AllDone && PtInRect(&rccol,pt))
		 for (i = 1 ; i <= Levels ; i++)
		 {
			 // if mouse in button[i]
			 if (PtInRect(&rclv[button = Levels - i], pt)) 
			 {
			  // toggle level-inclusion

				 IncludeLev[i] ^= 1 ;

			  // set the level button accordingly

				 ivrc(hWnd, &rclv[button], FALSE) ;

			  // recalculate Lambdas

				 Lambda(RIGHT) ;
				 Lambda(LEFT) ;
				 Lambda(BOTH) ;

			  // record Lambdas for display purposes

				 RecordLambdas() ;

			  // update result window and null profile
				 
				 ivrc(hWndRslt,   NULL, TRUE) ;
				 ivrc(hWndNPGraf, NULL, TRUE) ;
			 }
		 }
		break ;

        case WM_LBUTTONDOWN:

		  pt.x = LOWORD(lParam) ; // get mouse co-ords at left click
		  pt.y = HIWORD(lParam) ;

		  if (PtInRect(&rcTpole, pt))
		  {
			  dragtop = 1 ;
			  dragbot = 0 ;
			       dx = pt.x - rcTpole.left ;
				   dy = pt.y - rcTpole.top ;
		  }

		  if (PtInRect(&rcBpole, pt))
		  {
			  dragbot = 1 ;
			  dragtop = 0 ;
			       dx = pt.x - rcBpole.left ;
				   dy = pt.y - rcBpole.top ;
		  }
	
	// If not scanning or setting anything, and the cursor is in
	// the image, allow image resizing if it is not already resized.
	// This routine will also - one day - be used for setting a rectangle
	// limiting a pole-search region.

		  if (!scanning  &&
			  !setpole   &&
			  !setlevels &&
			   CurInImg  &&
			  !resized	 &&
			  !noselect  &&  // noselect disables the select button
			  (resizing  ||
			   setsearch)    // setsearch is intended for best-pole searches - still to come!
			  )  
		  {
		   // get the starting mouse position
			        ptstart.x = pt.x ;
		            ptstart.y = pt.y ;
		   // say we are resizing
		   //		 resizing = set ;
		   // get the current image rectangle in screen terms
			            pt3.x = rcimg.left ;
			            pt3.y = rcimg.top ;
			            ClientToScreen(hWnd,&pt3) ;
			    rcimgscr.left = pt3.x ;
			    rcimgscr.top  = pt3.y ;
			            pt3.x = rcimg.right ;
			            pt3.y = rcimg.bottom ;
			            ClientToScreen(hWnd,&pt3) ;
			  rcimgscr.right  = pt3.x ;
			  rcimgscr.bottom = pt3.y ;
		  // and keep the cursor inside it for now
			  ClipCursor(&rcimgscr) ;
		  }

		  if (autotrack && PtInRect(&rctl[Acp],pt))  // "Accept" button
		  {
			  ACP = 1 ;
			  ivrc(hWnd, &rctl[Acp], FALSE ) ;
		  }
		break ;

		case WM_LBUTTONUP:

			// Stop pole-dragging and free cursor
			if (dragtop) {dragtop = 0 ; ClipCursor(NULL) ;}
			if (dragbot) {dragbot = 0 ;	ClipCursor(NULL) ;}

			// Accept the resize or search inset 
			if ((resizing || setsearch )  &&
				!noselect  &&
				!scanning  &&
				!setpole   &&
				!setlevels &&
				 CurInImg)
			{
				prev = FALSE ;

			// Trap and ignore a "no change" situation
				if (ptstart.x == ptnow.x || ptstart.y == ptnow.y)
				  goto dont_bother ;

				
			// sort out order of vertices.
			// dimensions are client-relative, i.e. (0,0) is at top left.

				if (ptstart.x > ptnow.x) // cursor is to left of start
				{
					xa = ptnow.x ;
				    xb = ptstart.x ;
				}
				else                     // cursor is to right of start
				{
					xa = ptstart.x ;
					xb = ptnow.x ;
				}

				if (ptstart.y > ptnow.y) // cursor is above start
				{
					ya = ptnow.y ;
				    yb = ptstart.y ;
				}
				else					 // cursor is below start
				{
					ya = ptstart.y ;
					yb = ptnow.y ;
				}
			
			if (resizing && !setsearch)
			{
				resizing = reset ;	// not resizing now
				 resized = set ;	// we have resized
				     REZ = reset ;
				ClipCursor(NULL) ;	// free the cursor

				// Client-relative (Pixels)
				xacli = xa - rcimg.left ; // pixel position of top left
				yacli = ya - rcimg.top ;
				xbcli = xb - rcimg.left ; // pixel position of bottom right
				ybcli = yb - rcimg.top ;
				 wcli = xbcli - xacli ;	  // pixel width of selection
				 hcli = ybcli - yacli ;	  // pixel height of selection
		   

				// DDB-relative	   (Bits)

 			      xsa = MulDiv(dibwid, xacli, rcimg.right - rcimg.left) ;
				  pBudResults->SubImageX = xsa ;

			      ysa = MulDiv(dibhyt, yacli, rcimg.bottom - rcimg.top) ;	 // T.L.
				  pBudResults->SubImageY = ysa ;

				  ws = MulDiv(dibwid, wcli, rcimg.right - rcimg.left) ; // width
				  pBudResults->SubImageW = ws ;

				  xsb = xsa + ws ; 

				   hs = MulDiv(dibhyt,  hcli, rcimg.bottom - rcimg.top) ;	// height
		           pBudResults->SubImageH = hs ;

				  ysb = ysa + hs ; 

				   AdjustDisplays() ;
				   if(!batching)
				   {
				   stored = 0 ;
				   GetLineStorage() ;
				   }


			// Magnification is calculated in AdjustDisplays()
				   
				for (i = 1 ; i <= MAXLEVELS ; EdgeDone[i++] = NONE) ;
				
				Blink  = SetTimer(hWndBud,IDT_BTIMER, tBlink, NULL ) ;
				TOPSET = BOTSET = reset ;

				SendMessage(hWndRslt,WM_RESET,0,0L) ;
		        
				// Update Measurement Window
				ivrc(hWnd,NULL,TRUE) ; //prewipe all client area
				UpdateWindow(hWnd) ;

				// Update Results Window
				ivrc(hWndRslt,&rcrslt,TRUE) ;
				UpdateWindow(hWndRslt) ;

		msgbox = 1 ;
		MessageBox(hWnd,
        "Changing the image has invalidated the\n" \
        "Pole placements and any measurements\n" \
        "which may have been made.\n\n" \
        "Please place both poles again.",
		"Image dimensions changed",MB_ICONINFORMATION | MB_OK ) ;
		msgbox = 0 ;

		RecordDimensions() ;
		toArchive = 1 ;
			}

		if (setsearch && !resizing)
		{
			SetRect(&rcSearch, xa, ya, xb, yb) ;
			setsearch = 0 ;
			searchset = 1 ;
			ivrc(hWnd, NULL, TRUE) ;
		}

dont_bother: ;
			}

		  // get image-relative mouse position

		  CliToImg(&p,&pt) ;
		  xm = p.x ; 
          ym = p.y ;

	// If left click in neither level-button nor image,
	// allow free ranging scan if it is locked: i.e., cancel cursor
	// constraint and deselect the selected button

		 if ( scanning &&
			 !CurInImg &&
			 !(PtInRect(&rccol,pt)) &&
			  Locked)
			 SendMessage(hWnd,WM_COMMAND,RELEASE_LOCK,0L) ;

	// A left click accepts the current
	// mouse position as a pole.
		 if ( setpole &&
			 !setlevels &&
			 !scanning &&
			 !calibrating &&
			  CurInImg)    
		     SendMessage(hWnd,WM_COMMAND,ENTER_ACCEPT_POLE,0L) ;
	
	// A left click accepts the current
	// mouse position as a calibration mark
		 if ( calibrating &&
			 !setpole &&
			 !scanning &&
			 !setlevels &&
			  CurInImg)
		 {
		   POINT B ;
// DDB-relative: by proportion, we have 
// (xMk-xsa)/ws = (pt.x-rcimg.left)/(rcimg.right-rcimg.left) and
// (yMk-ysa)/hs = (pt.y-rcimg.top )/(rcimg.bottom-rcimg.top),
// which implies that..

 //xMk = MulDiv(ws, pt.x - rcimg.left, bimwid) + xsa ;
 //yMk = MulDiv(hs, pt.y - rcimg.top , bimhyt) + ysa ;

		     CliToBuff(&B, &pt) ;

		     xMk = B.x ;
		     yMk = B.y ;
		  
			 if (SETCAL1)   // we are calibrating on the first mark
			 {
			  CAL_1_AVAILABLE = 1 ;
	          xMark1 = (double)xMk ; xBCal1 = xMk ; xCal1 = pt.x ;
	          yMark1 = (double)yMk ; yBCal1 = yMk ; yCal1 = pt.y ;
			 }
		     else			// we are calibrating on the second mark
			 {
			  CAL_2_AVAILABLE = 1 ;
	          xMark2 = (double)xMk ; xBCal2 = xMk ; xCal2 = pt.x ;
	          yMark2 = (double)yMk ; yBCal2 = yMk ; yCal2 = pt.y ;
			 }
			 SendMessage(hWnd,WM_COMMAND,ENTER_ACCEPT_MARK,0L) ;
		 }

		 // enable scanning option if not setting anything

         if (
			 PtInRect(&rctl[Lsc],pt) &&
			 !setlevels && 
			 !setpole
			)
		 {
             Clicked[Lsc] = 1 ;
			 KillTip(hWnd, Lsc) ;
			 SendMessage(hWnd,WM_COMMAND,TOGGLE_SCAN,0L) ;
		 }


		 // Turn scan graphs on or off

		 if (PtInRect(&rctl[Gra],pt)) // in Graphs button
		 {
             Clicked[Gra] = 1 ;
			 KillTip(hWnd, Gra) ;
			 SendMessage(hWnd,WM_COMMAND,TOGGLE_GRAPHS,0L) ;
		 }
		 
		 if (PtInRect(&rctl[Gry],pt)) // in grayscale/colour button
		 {
             Clicked[Gry] = 1 ;
			 KillTip(hWnd, Gry) ;
			 SendMessage(hWnd,WM_COMMAND,TOGGLE_COLOUR,0L) ;
		 }
		 
		 if (PtInRect(&rctl[Hip],pt)) // in high pole button
		 {
             Clicked[Hip] = 1 ;
			 KillTip(hWnd, Hip) ;
			 SendMessage(hWnd,WM_COMMAND,SET_HI_POLE,0L) ;
		 }

		 if (PtInRect(&rctl[Lop],pt)) // in low pole button
		 {
             Clicked[Lop] = 1 ;
			 KillTip(hWnd, Lop) ;
			 SendMessage(hWnd,WM_COMMAND,SET_LO_POLE,0L) ;
		 }

		 if (PtInRect(&rctl[Ca1],pt)) // in first calibrate button
		 {
             Clicked[Ca1] = 1 ;
			 KillTip(hWnd, Ca1) ;
			 SendMessage(hWnd,WM_COMMAND,CALIBRATE_MEASURE_ONE,0L) ;
		 }

		 if (PtInRect(&rctl[Ca2],pt)) // in second calibrate button
		 {
             Clicked[Ca2] = 1 ;
			 KillTip(hWnd, Ca2) ;
			 SendMessage(hWnd,WM_COMMAND,CALIBRATE_MEASURE_TWO,0L) ;
		 }

		 if (PtInRect(&rctl[Rez],pt) && !noselect) // in resize image button
		 {
             Clicked[Rez] = 1 ;
			 KillTip(hWnd, Rez) ;
			 SendMessage(hWnd,WM_COMMAND,RESIZE_IMAGE,0L) ;
		 }

		 if (PtInRect(&rctl[Aut],pt)) // in autotrack button
		 {
             Clicked[Aut] = 1 ;
			 KillTip(hWnd, Aut) ;
			 SendMessage(hWnd,WM_COMMAND,AUTOMEAS_BUD,0L) ;
		 }

		 if (autotrack && PtInRect(&rctl[Acp],pt)) // in accept track button
		 {
             Clicked[Acp] = 1 ;
			 KillTip(hWnd, Acp) ;
			 SendMessage(hWnd,WM_COMMAND,ACCEPT_TRACK,0L) ;
		 }

		 if (PtInRect(&rctl[Prm],pt)) // in Params button
		 {
             Clicked[Prm] = 1 ;
			 KillTip(hWnd, Prm) ;
			 SendMessage(hWnd,WM_COMMAND,SET_TRACK_PARMS,0L) ;
		 }

		 if (PtInRect(&rctl[Alf],pt)) // in track left side button
		 {
             Clicked[Alf] = 1 ;
			 KillTip(hWnd, Alf) ;
			 SendMessage(hWnd,WM_COMMAND,AUTOMEAS_LFT,0L) ;
		 }

		 if (PtInRect(&rctl[Art],pt)) // in track right side button
		 {
             Clicked[Art] = 1 ;
			 KillTip(hWnd, Art) ;
			 SendMessage(hWnd,WM_COMMAND,AUTOMEAS_RYT,0L) ;
		 }

		 if (scanning && PtInRect(&rctl[Scc], pt)) // in line scan colour select button
		 {
			 if (PtInRect(&rctl[Lsa], pt))
			 {
				 scancolour = 0 ;
                 Clicked[Lsa] = 1 ;
			     KillTip(hWnd, Lsa) ;
				 LSA = 1 ; LSR = 0 ; LSG = 0 ; LSB = 0 ;
			 }

			 if (PtInRect(&rctl[Lsr], pt))
			 {
				 scancolour = 1 ;
                 Clicked[Lsr] = 1 ;
			     KillTip(hWnd, Lsr) ;
				 LSA = 0 ; LSR = 1 ; LSG = 0 ; LSB = 0 ;
			 }

			 if (PtInRect(&rctl[Lsg], pt))
			 {
				 scancolour = 2 ;
                 Clicked[Lsg] = 1 ;
			     KillTip(hWnd, Lsg) ;
				 LSA = 0 ; LSR = 0 ; LSG = 1 ; LSB = 0 ;
			 }

			 if (PtInRect(&rctl[Lsb], pt))
			 {
				 scancolour = 3 ;
                 Clicked[Lsb] = 1 ;
			     KillTip(hWnd, Lsb) ;
				 LSA = 0 ; LSR = 0 ; LSG = 0 ; LSB = 1 ;
			 }

		   ivrc(hWnd, &rctl[Scc], TRUE) ;
		 }

		 if (PtInRect(&rctl[Lev],pt)) // in Levels button
		 {
             Clicked[Lev] = 1 ;
			 KillTip(hWnd, Lev) ;
			 LLV ^= 1 ;                        // toggle set levels mode
			 setlevels = LLV ;	               // match flag to mode
			 ivrc(hWnd,&rctl[Lev],FALSE) ;
			 
			 // Turn poleset off if on when setlevels asserted
			 // Set button(s) to off if on. Turn off scanning if on.

			 if (setlevels)
		     {
				 setpole = scanning = graphing = 0 ;
				 LSC = btn_up ;
				 ivrc(hWnd,&rctl[Lsc],FALSE) ;
				 SendMessage(hWndScan,WM_COMMAND,IDM_SHOW_SCAN,0L) ;
				 
				 if (HIP)
				 {
				 HIP = btn_up ;
				 ivrc(hWnd,&rctl[Hip],FALSE) ;
				 }
				 if (LOP)
				 {
				 LOP = btn_up ;
				 ivrc(hWnd,&rctl[Lop],FALSE) ;
				 }

			  //get or confirm the number of measure levels
			  
			     Confirm = DialogBox(
					                 hInst,
					                 MAKEINTRESOURCE(IDD_SET_HEIGHTS),
					                 (HWND)NULL,
						             (DLGPROC)HytDlgProc
									) ;

			 if (Confirm == IDOK) 
			    {
			 // accommodate new column of buttons
				 AdjustDisplays() ;	
             //wipe current button column
				 ivrc(hWnd,&rccol,TRUE) ;
			 //throw away current poles and measurements
				 ResetMeasure(hWnd, LEV, EdgeDone) ;
			 //but make stealthy selection
				 LevelSelect = 1 ;
				   toArchive = 1 ;
			     ivrc(hWnd, &rctl[Lev], TRUE) ;
				 ivrc(hWndRslt,   NULL, TRUE) ;
				if (shownullgraph)
				 ivrc(hWndNPGraf, NULL, TRUE) ;
				 ivrc(hWnd,       NULL, TRUE) ;

			 // if the bud has been autotracked,
			 // measure and calculate at once for
			 // the new set of levels
				 if (autotracked)
				 {
					 MeasureGrid(pMeasure) ;
					 MeasureTrackedBud(Tk) ;
				  if (!AllDone)
				   {
					  char note[100] ;

					  sprintf(note,
						  "Measurement Incomplete." \
					"\n\n\nPlease check that Tracks extend" \
						"\nsufficiently on the bud's profiles.") ;
					  msgbox = 1 ;	  
					  MessageBox(hWndBud,
						         note,
								"New Measure-Height Distribution",
						         MB_ICONEXCLAMATION|MB_OK) ;
					  msgbox = 0 ;
				   }
				 }
		    }

				 // done with setting levels,
			     // set levels button to off
				 // de-assert level setting.
				 setlevels = reset ;
				 LLV = btn_up ;
				 ivrc(hWnd,&rctl[Lev],FALSE) ;
				 UpdateWindow(hWnd) ;
		    }
		 }

		 //========================================================
		 //		Do the buttons communicate?
		 //========================================================

	   if (PtInRect(&rctl[Btn80],pt))
	   {  MessageBeep(MB_ICONASTERISK) ; }

	   if (PtInRect(&rctl[Btn81],pt))
	   {  MessageBeep(MB_ICONEXCLAMATION) ; }

	   if (PtInRect(&rctl[Btn82],pt))
	   {  MessageBeep(MB_ICONHAND) ; }

	   if (PtInRect(&rctl[Btn83],pt))
	   {  MessageBeep(MB_ICONASTERISK) ; }

	   if (PtInRect(&rctl[Btn84],pt))
	   {  MessageBeep(MB_ICONEXCLAMATION) ; }

	   if (PtInRect(&rctl[Btn85],pt))
	   {  MessageBeep(MB_OK) ; }


		 //========================================================
		 
		 // if, while we're in scan mode, the mouse is clicked
		 // in the button column, poll the column of buttons
		 // for any selected.
		 if (scanning)
		 {
		 if (PtInRect(&rccol,pt))
		 for (i = 1 ; i <= Levels ; i++)
		 {
			 // if mouse in button[i]
			 if (PtInRect(&rclv[button = Levels - i], pt)) 
			 {
				 oldbutton = Levels - LevelSelect ;
				 LEV[oldbutton] = btn_up ; // cancel former selection
			  	 ivrc(hWnd,&rclv[oldbutton],FALSE) ;
				 LEV[button] = btn_down ;  // set button i to selected
				 LevelSelect = i ;		   // record selection
			     ivrc(hWnd,&rclv[button],FALSE) ;
				 // flag up that a level is selected
				 //(for cursor-trapping)
				 Locked = JustLocked = set ;
				 // give level in Bud window's title bar
				 strcpy(szBudWindowTit1,_strlwr(DropPath(szFile))) ;
				 sprintf(string,": locked on level %d of %d",
					             LevelSelect, Levels) ;
				 strcat(szBudWindowTit1,string) ;
				 SetWindowText(hWndBud,szBudWindowTit1) ;
			 }
		   }
		 }

		// If we are locked in a level, a left click accepts the
		// current mouse position as a bud edge, and records it
		// as a left edge if the mouse is to the left of the 
		// current bud axis, else as a right edge. If both edges
		// have been measured, then the bud "diameter" at the level
		// is also recorded.
	
		 if (scanning & Locked & stored & CurInImg)
		 SendMessage(hWnd,WM_COMMAND,ENTER_ACCEPT_MEASURE,0L) ;

        break ;

        case WM_MOVE:
        case WM_SIZE:
        case WM_WINDOWPOSCHANGED:
		previousline = reset ;
        AdjustDisplays() ;
        ivrc(hWnd, NULL, TRUE) ;
        UpdateWindow(hWnd) ;
        if (scanning) ShowSmoothing(hWndScan) ;
        return 0 ;
        break ;
        
        case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps) ;
        if (gotimage)
        { 
         hmemDCc = CreateCompatibleDC(hdc) ;
         GetObject(bmLSC, sizeof(BITMAP), &bm ) ;
            oBmc = SelectObject(hmemDCc, bmLSC) ;
			{
				char blank[] = {'\0'} ;

			if (strlen(DropPath(szFile)) != 0) 
		  filetitle = DropExt(DropPath(szFile)) ;
	   else
		  filetitle = blank ;

	GetTextExtentPoint32(hdc, filetitle, strlen(filetitle), &sz) ;
	   T.x = rcimg.left + 1 ;
	   T.y = rcimg.bottom + (sz.cy + 3) ;
	   T.tC = Cr[YELLOW] ;
	   T.bC = Cr[BLACK] ;
	   PutText(hdc, &T, filetitle) ;
			}

	   if (scanning) // colour on which to scan
	   {RECT rc ;
		if( LSA ) { SelectObject(hmemDCc, bmLSA) ; rc = rcLsa ; } // All
		if( LSR ) { SelectObject(hmemDCc, bmLSR) ; rc = rcLsr ; } // red
		if( LSG ) { SelectObject(hmemDCc, bmLSG) ; rc = rcLsg ; } // green
		if( LSB ) { SelectObject(hmemDCc, bmLSB) ; rc = rcLsb ; } // blue

               BitBlt(hdc, rc.left,	  // show button
                           rc.top,
                           rc.right - rc.left,
                           rc.bottom - rc.top,
                           hmemDCc, 0, 0, SRCCOPY ) ;
	   }

	   if( !LSC )                            // for "Scan" button
               SelectObject(hmemDCc, bmLSC) ;// show enabled but unselected
            else
               SelectObject(hmemDCc, bmLSCO) ;// show selected

               BitBlt(hdc, rctl[Lsc].left,	  // show button
                           rctl[Lsc].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !GRA )							   // for "graphs" button
               SelectObject(hmemDCc, bmGRA) ;  // show unselected
            else
               SelectObject(hmemDCc, bmGRAO) ; // show selected

               BitBlt(hdc, rctl[Gra].left,	  // show button
                           rctl[Gra].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !REZ )							   // for "image resize" button
	    {
		   if (resized)
		   {
			 if (!noselect)
                SelectObject(hmemDCc, bmREZO) ; // show done
			 else
                SelectObject(hmemDCc, bmREZH) ; // show done, disabled
		   }
            else
			{
			if (!noselect)
               SelectObject(hmemDCc, bmREZ) ;  // show undone
			else
               SelectObject(hmemDCc, bmREZD) ; // show undone, disabled
			}
	    }
			else
               SelectObject(hmemDCc, bmRZG) ;  // show doing it

               BitBlt(hdc, rctl[Rez].left,	  // show button
                           rctl[Rez].top,
                           rctl[Rez].right  - rctl[Rez].left,
                           rctl[Rez].bottom - rctl[Rez].top,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !AUT )							   // for "Track" button
	   {
		   if (autotracked)      // if all auto measured
               SelectObject(hmemDCc, bmAUTD) ; // show done
            else
               SelectObject(hmemDCc, bmAUT) ;  // show undone
	   }
			else
               SelectObject(hmemDCc, bmAUTO) ;  // show doing it

               BitBlt(hdc, rctl[Aut].left,	  // show button
                           rctl[Aut].top,
                           rctl[Aut].right  - rctl[Aut].left,
                           rctl[Aut].bottom - rctl[Aut].top,
                      hmemDCc, 0, 0, SRCCOPY ) ;


	   if( !ALF )				// for track left side button
	   {
		   if (autolftdone)     // if left side tracked
               SelectObject(hmemDCc, bmALFD) ; // show done
            else
               SelectObject(hmemDCc, bmALF) ;  // show undone
	   }
			else
               SelectObject(hmemDCc, bmALFO) ; // show doing it

               BitBlt(hdc, rctl[Alf].left,	   // show button
                           rctl[Alf].top,
                           rctl[Alf].right  - rctl[Alf].left,
                           rctl[Alf].bottom - rctl[Alf].top,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !ART )			    // for track right side button
	   {
		   if (autorytdone)     // if right side tracked
               SelectObject(hmemDCc, bmARTD) ; // show done
            else
               SelectObject(hmemDCc, bmART) ;  // show undone
	   }
			else
               SelectObject(hmemDCc, bmARTO) ; // show doing it

               BitBlt(hdc, rctl[Art].left,	   // show button
                           rctl[Art].top,
                           rctl[Art].right  - rctl[Art].left,
                           rctl[Art].bottom - rctl[Art].top,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !ACP )			// for accept track button
               SelectObject(hmemDCc, bmACP) ; 
            else
               SelectObject(hmemDCc, bmACPO) ;  

               BitBlt(hdc, rctl[Acp].left,	  // show button
                           rctl[Acp].top,
                           rctl[Acp].right  - rctl[Acp].left,
                           rctl[Acp].bottom - rctl[Acp].top,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !PRM )			// for parameters button
               SelectObject(hmemDCc, bmPRM) ; 
            else
               SelectObject(hmemDCc, bmPRMO) ;  

               BitBlt(hdc, rctl[Prm].left,	  // show button
                           rctl[Prm].top,
                           rctl[Prm].right  - rctl[Prm].left,
                           rctl[Prm].bottom - rctl[Prm].top,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   switch( which )	// for Grayscale,Colour or Significance button
	   {
	    case COLOUR:	SelectObject(hmemDCc, bmCLR)  ; break ;
	    case GRAY:	    SelectObject(hmemDCc, bmGRY ) ;	break ;
	    case SIGNIF:	SelectObject(hmemDCc, bmSGF ) ;	break ;
	   }
               
               BitBlt(hdc, rctl[Gry].left,	  // show button
                           rctl[Gry].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;


	   if( !LLV )							   // for Levels button
               SelectObject(hmemDCc, bmLEV) ;
            else
               SelectObject(hmemDCc, bmLEVO) ;

               BitBlt(hdc, rctl[Lev].left,	  // show button
                           rctl[Lev].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !LOP )							   // for Lo Pole button
	   {
		   if (BOTSET)
		       SelectObject(hmemDCc, bmLOD) ; // show "done"
	        else
			{
				if (!blinklo)				  // blink button
               SelectObject(hmemDCc, bmLOP) ; // show off, not done
				else
			   SelectObject(hmemDCc, bmBOP) ;
			}
	   }
            else
               SelectObject(hmemDCc, bmLOPO) ; // show selected, not done

               BitBlt(hdc, rctl[Lop].left,	   // show button
                           rctl[Lop].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;
       
	   if( !HIP )							   // for Hi pole button
		 {
		  if (TOPSET)
			   SelectObject(hmemDCc, bmHID) ;  // show done
		  else
		  {
		      if (!blinkhi)					  // blink button
			  SelectObject(hmemDCc, bmHIP) ;  // show unselected, not done
			  else
			  SelectObject(hmemDCc, bmBIP) ;
		  }
		 }
            else
               SelectObject(hmemDCc, bmHIPO) ;	// show selected, not done


               BitBlt(hdc, rctl[Hip].left,	  // show button
                           rctl[Hip].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

         GetObject(bmCAL1, sizeof(BITMAP), &bm ) ;

	   if( !CAL1 )							   // for "Calibrate 1" button
	   {
         if (CAL1SET)
			   SelectObject(hmemDCc, bmCAL1D) ;	// show unpressed, done
		    else
			{
			   if (!blinkhi1)
		       SelectObject(hmemDCc, bmCAL1) ;	// show unpressed, to do
			   else
			   SelectObject(hmemDCc, bmCAL1B) ;
			}
		 
	   }
            else
               SelectObject(hmemDCc, bmCAL1O) ;	// show pressed, doing it

               BitBlt(hdc, rctl[Ca1].left,	  // show button
                           rctl[Ca1].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !CAL2 )							   // for "Calibrate 2" button
	   {
		   if (CAL2SET)
			   SelectObject(hmemDCc, bmCAL2D) ; // show unpressed, done
		   else
		   {
			   if (!blinklo1)
               SelectObject(hmemDCc, bmCAL2) ;	// show unpressed, to do
			   else
			   SelectObject(hmemDCc, bmCAL2B) ;
		   }
		   
	   }
            else
               SelectObject(hmemDCc, bmCAL2O) ;	// show pressed, doing it

               BitBlt(hdc, rctl[Ca2].left,	  // show button
                           rctl[Ca2].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	    if (TOPSET & BOTSET)
		 {
            GetObject(bmHYTN, sizeof(BITMAP), &bm ) ;

            SetStretchBltMode(hdc, BLACKONWHITE) ;

		  for ( i = 1 ; i <= Levels ; i++)
		  {
			button = Levels - i ;

			if (AllDone && !IncludeLev[i])
			{
			if (LEV[button]==btn_up)
				bmap = bmEXCLU ;  // level is excluded from lambda calculations
			else
				bmap = bmEXCLO ;  // level is excluded but selected for scanning
			}
			else
			{
			if (LEV[button]==btn_up)
			  switch(EdgeDone[i])  // show button in unselected state
			 {
               case NONE: bmap = bmHYTN ; break ; //  none done
               case LEFT: bmap = bmHYTL ; break ; //  left done
			   case RIGHT:bmap = bmHYTR ; break ; // right done
			   case BOTH: bmap = bmHYTB ; break ; //  both done
			   default : break ;
			 }
			else
			  switch(EdgeDone[i])  // show button in selected state
			 {
               case NONE: bmap = bmHYTNO ; break ; //  none done
               case LEFT: bmap = bmHYTLO ; break ; //  left done
			   case RIGHT:bmap = bmHYTRO ; break ; // right done
			   case BOTH: bmap = bmHYTBO ; break ; //  both done
			   default : break ;
			 }
			}
				
			oBmc = SelectObject(hmemDCc, bmap) ;

			  StretchBlt(hdc,
			             rclv[button].left,
						 rclv[button].top,
						 rclv[button].right  - rclv[button].left,
						 rclv[button].bottom - rclv[button].top,
						 hmemDCc,
						 0, 0,
						 bm.bmWidth,
						 bm.bmHeight,
						 SRCCOPY) ;
		  }
		}

		//====================================
		// Duplicated Results-window buttons
		//====================================
/***
		  	   if( !DIA )						
               SelectObject(hmemDCc, bmDIA) ;
            else
               SelectObject(hmemDCc, bmDIAO) ;

               BitBlt(hdc, rctl[Btn81].left,
                           rctl[Btn81].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !PRJ )
               SelectObject(hmemDCc, bmPRJ) ;
            else
               SelectObject(hmemDCc, bmPRJO) ;

               BitBlt(hdc, rctl[Btn80].left,
                           rctl[Btn80].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !LEF )
               SelectObject(hmemDCc, bmLEF) ;
            else
               SelectObject(hmemDCc, bmLEFO) ;

               BitBlt(hdc, rctl[Btn82].left,
                           rctl[Btn82].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !RYT )
               SelectObject(hmemDCc, bmRYT) ;
            else
               SelectObject(hmemDCc, bmRYTO) ;

               BitBlt(hdc, rctl[Btn83].left,
                           rctl[Btn83].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;

	   if( !NPR )								// Null Profile Control
	   {
		   if (!(RYT || LEF || DIA))         	// if no PC selected,
               SelectObject(hmemDCc, bmNULD) ;	// show off and disabled	
		   else									// else
               SelectObject(hmemDCc, bmNUL) ;	// show off and enabled 
	   }
            else								// a PC selected,
               SelectObject(hmemDCc, bmNULO) ;	// show on

               BitBlt(hdc, rctl[Btn84].left,
                           rctl[Btn84].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;
	   

	   if (gotimage) // Allow Details dialogue only if image present
	   {
	   if( !DTL )
               SelectObject(hmemDCc, bmDTL) ;
            else
               SelectObject(hmemDCc, bmDTLO) ;

               BitBlt(hdc, rctl[Btn85].left,
                           rctl[Btn85].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDCc, 0, 0, SRCCOPY ) ;
	   }

 ***/		 
		  SelectObject(hmemDCc,oBmc) ;
          DeleteDC(hmemDCc) ;


          // get the image

		  // This is the bud image
		  // to be displayed in
		  // the Measure Window.

		  switch (which)
		  {
		  case GRAY:
		   hBm = _ISRGBToHBITMAP(pGRY, dibwid, dibhyt, NULL, hdc) ;
		   break ;

		  case SIGNIF:
		   hBm = _ISRGBToHBITMAP(pSTA, dibwid, dibhyt, NULL, hdc) ;
		   break ;

		  case COLOUR:
		  default:
		   hBm = _ISRGBToHBITMAP(pRGB, dibwid, dibhyt, NULL, hdc) ;
		   break ;
		  }

		  hmemDC = CreateCompatibleDC(hdc) ;			// memory DC
          oBm = SelectObject(hmemDC, hBm) ;				// select into DC
          SetStretchBltMode(hdc, COLORONCOLOR) ;		// set stretch mode
          
          StretchBlt(hdc,rcimg.left,					// display the Image
                         rcimg.top,
                         rcimg.right  - rcimg.left,
                         rcimg.bottom - rcimg.top,
					  hmemDC,
					  xsa,
					  ysa,
					  ws,
					  hs,
                      SRCCOPY) ;

		  if (LevelPicked)
		  {
			  int h ;
			  oBm = SelectObject(hmemDC, LftArrow) ;
			  BitBlt(hdc,
				     rccolrt.left + 4,
					(rclv[h = Levels - LevelPicked].top + 
					 rclv[h].bottom) / 2 - 6,
					 8, 12,
				     hmemDC,
					 0, 0, SRCCOPY) ;
			  SelectObject(hmemDC, oBm) ;
		  }

		  if (CAL1SET && CAL_1_AVAILABLE)
		  {
			  Bf.x = xBCal1 ;
			  Bf.y = yBCal1 ;
			  BuffToCli(&Sc, &Bf) ;
			  DrawCross(hWnd, invert, Sc.x, Sc.y, 8, bluePen) ;
		  }

		  if (CAL2SET && CAL_2_AVAILABLE)
		  {
			  Bf.x = xBCal2 ;
			  Bf.y = yBCal2 ;
			  BuffToCli(&Sc, &Bf) ;
			  DrawCross(hWnd, invert, Sc.x, Sc.y, 8, yellowPen) ;
		  }

          SelectObject(hmemDC,oBm) ;
          DeleteObject(hBm) ;
          DeleteDC(hmemDC) ;
        }
        EndPaint(hWnd, &ps) ;
        return 0 ;
        break ;

        case WM_TIMER:

		switch(wParam)
		{
		  case IDT_SELFTRKTIMER:
			  if (jumpmouse && CurInImg)
			  {
				 GetCursorPos(&crpt) ;
				 SetCursorPos((int)crpt.x, (int)crpt.y - jumpsize) ;
			  }
			  return 0 ;

		  case IDT_RTIMER:		// controls the rotating cursor

		  if (currotate)
		  {
		   k++ ; if (k > 4) k = 1 ;
		   oldCursor = SetCursor(hRotCur[k]) ;
		  }
		  return 0 ;

		  case IDT_BTIMER:	   // controls the pole-setting button blink
		  if (!TOPSET & !setpole )
		  {
			blinkhi ^= 1 ;
		    ivrc(hWnd,&rctl[Hip],FALSE) ;
		  }

		  if (!BOTSET & !setpole)
		  {
			blinklo ^= 1 ;
		    ivrc(hWnd,&rctl[Lop],FALSE) ;
		  }
		  return 0 ;

		  case IDT_BTIMER1:	   // controls the calibration-button blink.
		  if (!CAL1SET & !calibrating )
		  {
			blinkhi1 ^= 1 ;
		    ivrc(hWnd,&rctl[Ca1],FALSE) ;
		  }

		  if (!CAL2SET & !calibrating)
		  {
			blinklo1 ^= 1 ;
		    ivrc(hWnd,&rctl[Ca2],FALSE) ;
		  }
		  return 0 ;

		  case IDT_VOCTIMER:

		   // This timer was started by the
		   // cursor having been in the control
		   // for longer than the delay period. If
		   // the cursor is still there now,
		   // play the tip.

			GetCursorPos(&cupt) ;
			ScreenToClient(hWnd,&cupt) ;
			if (PtInRect(&rctl[UseBtn],cupt))
			{
				PlaySound(szVocTipWav[UseBtn], NULL, SND_ASYNC) ;
			}
			KillTimer(hWnd,IDT_VOCTIMER) ;
			return 0 ;

			case IDT_TIPDWELL:

			// This dwell timer came on when
			// the tip was shown.
			// If the cursor is now still in
			// the button, kill the tip, and
			// say there is no current tip.

			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 DestroyWindow(hWndInfo[UseCtl]) ;
				 CurrentTip = (HWND)NULL ;
				 hWndOfCurrentTip = (HWND)NULL ;
			 }
		  // whatever else happens, kill the timer
			 KillTimer(hWnd, IDT_TIPDWELL) ;
			 Dwelling[UseCtl] = 0 ;
			 return 0L ;
			
			case IDT_TIPDEFER:

			 // whatever else happens, kill this timer
			 KillTimer(hWnd,IDT_TIPDEFER) ;
			 Deferred[UseCtl] = 0 ;

			 GetCursorPos(&cupt) ;		    // is ind'p't of WndProc
			 ScreenToClient(hWnd,&cupt) ;	// and mouse capture

			 // This timer came on after the
			 // in-button delay.
			 // If the cursor is now still in the
			 // indicated control, show the
			 // corresponding tip, and
			 // start the dwell timer.
			 
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 PutTip(hWnd, 0, 3) ;
			 }
			  return 0 ;

		  default:
			  break ;
		}
		return 0L ;
		break ;

        case WM_CREATE:
		hAccel = LoadAccelerators(hInst,MAKEINTRESOURCE(IDR_ACCELERATOR1)) ;
         bmLSA = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SCANONALL)) ;
         bmLSR = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SCANONRED)) ;
         bmLSG = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SCANONGREEN)) ;
         bmLSB = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SCANONBLUE)) ;
         bmLSC = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_LINE_SCAN)) ;
        bmLSCO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_LINE_SCAN_ON)) ;
         bmGRA = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GRAPHS)) ;
        bmGRAO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GRAPHS_ON)) ;
		 bmGRY = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GRAY)) ;
		 bmCLR = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CLR)) ;
		 bmSGF = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SIGNIF)) ;
		 bmHIP = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SET_HI_POLE)) ;
		bmHIPO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SET_HI_POLE_ON)) ;
		 bmHID = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SET_HI_POLE_DONE)) ;
		 bmLOP = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SET_LO_POLE)) ;
		bmLOPO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SET_LO_POLE_ON)) ;
		 bmLOD = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SET_LO_POLE_DONE)) ;
		bmCAL1 = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALIBRATE_ONE)) ;
	   bmCAL1B = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALIB1_BLINK)) ;
	   bmCAL1O = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALIBRATE_ONE_ON)) ;
	   bmCAL1D = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALIB1_DONE)) ;
		bmCAL2 = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALIBRATE_TWO)) ;
	   bmCAL2B = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALIB2_BLINK)) ;
	   bmCAL2O = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALIBRATE_TWO_ON)) ;
	   bmCAL2D = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CALIB2_DONE)) ;
		 bmLEV = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SET_LEVELS)) ;
		bmLEVO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SET_LEVELS_ON)) ;
		bmHYTN = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_HYT_NONE)) ;
	   bmHYTNO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_HYT_NONE_ON)) ;
	    bmHYTL = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_HYT_LEFT)) ;
	   bmHYTLO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_HYT_LEFT_ON)) ;
		bmHYTR = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_HYT_RYT)) ;
	   bmHYTRO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_HYT_RYT_ON)) ;
	    bmHYTB = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_HYT_BOTH)) ;
	   bmHYTBO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_SELECT_HYT_BOTH_ON)) ;
	   bmEXCLU = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_HYT_EXCLUDE)) ;
	   bmEXCLO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_HYT_EXCLUDE_SEL)) ;
		 bmBIP = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BLINK_HI)) ;
		 bmBOP = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_BLINK_LO)) ;
		 bmREZ = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_RECT_SELECT)) ;
		bmREZD = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_RECT_SELECT_DISABLED)) ;
		bmREZO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_RECT_SELECTED)) ;
		bmREZH = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_RECT_SELECTED_DISABLED)) ;
		 bmRZG = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_RECT_SELECTING)) ;
		 bmAUT = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO)) ;
		bmAUTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO_ON)) ;
		bmAUTD = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO_DONE)) ;
		 bmALF = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO_LFT)) ;
		bmALFO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO_LFT_ON)) ;
		bmALFD = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO_LFT_DONE)) ;
		 bmART = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO_RYT)) ;
		bmARTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO_RYT_ON)) ;
		bmARTD = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_AUTO_RYT_DONE)) ;
		bmACP  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ACCEPT_TRACK)) ;
		bmACPO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ACCEPT_TRACK_ON)) ;
		bmPRM  = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_TRACK_PARMS)) ;
		bmPRMO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_TRACK_PARMS_ON)) ;
	  LftArrow = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_LEFT_ARROW)) ;

		 icoTP  = LoadIcon(hInst, MAKEINTRESOURCE(IDI_TP_DRAG)) ;
		 icoBP  = LoadIcon(hInst, MAKEINTRESOURCE(IDI_BP_DRAG)) ;
		 icoPtr = LoadIcon(hInst, MAKEINTRESOURCE(IDI_DPTR)) ;
		 
       hTarget = LoadCursor(hInst,MAKEINTRESOURCE(IDC_TARGET_FREE)) ;
      hTargetF = LoadCursor(hInst,MAKEINTRESOURCE(IDC_TARGET_FREE_FULL)) ;
   hTargetLock = LoadCursor(hInst,MAKEINTRESOURCE(IDC_TARGET_LOCKED)) ;
  hTargetLockF = LoadCursor(hInst,MAKEINTRESOURCE(IDC_TARGET_LOCKED_FULL)) ;
      hTargetW = LoadCursor(hInst,MAKEINTRESOURCE(IDC_TARGET_FREE_WIDE)) ;
  hTargetLockW = LoadCursor(hInst,MAKEINTRESOURCE(IDC_TARGET_LOCKED_W)) ;
    hRotCur[1] = LoadCursor(hInst,MAKEINTRESOURCE(IDC_ROT_CUR1)) ;
    hRotCur[2] = LoadCursor(hInst,MAKEINTRESOURCE(IDC_ROT_CUR2)) ;
    hRotCur[3] = LoadCursor(hInst,MAKEINTRESOURCE(IDC_ROT_CUR3)) ;
    hRotCur[4] = LoadCursor(hInst,MAKEINTRESOURCE(IDC_ROT_CUR4)) ;
	    hDpeak = LoadCursor(hInst,MAKEINTRESOURCE(IDC_ON_DIFF_PEAK)) ;
  hTracklftCur = LoadCursor(hInst,MAKEINTRESOURCE(IDC_TRACK_CUR_LFT)) ;
  hTrackrytCur = LoadCursor(hInst,MAKEINTRESOURCE(IDC_TRACK_CUR_RYT)) ;


	   hAccel2a = LoadAccelerators(hInst,MAKEINTRESOURCE(IDR_ACCELERATOR2)) ;
         bmPRJa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PROJECTIVE)) ;
        bmPRJOa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_REGRESSION)) ;
         bmLEFa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_LEFT)) ;
        bmLEFOa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_LEFT_ON)) ;
         bmRYTa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_RIGHT)) ;
        bmRYTOa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_RIGHT_ON)) ;
		 bmDIAa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_DIAMETER)) ;
		bmDIAOa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_DIAMETER_ON)) ;
		 bmDTLa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GIVE_DETAILS)) ;
		bmDTLOa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GIVE_DETAILS_ON)) ;
		 bmNULa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NULL_PROF)) ;
		bmNULOa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NULL_PROF_ON)) ;
		bmNULDa = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NULL_PROF_DIS)) ;

        return 0L ;
         break ; 
        
        case WM_DESTROY:
		if (TkParmDlg != (HWND)NULL)
	    DestroyWindow(TkParmDlg) ;
		if (SigDlg != (HWND)NULL)
	    DestroyWindow(SigDlg) ;

		DeleteObject(bmPRJa) ;
        DeleteObject(bmLEFa) ;
        DeleteObject(bmRYTa) ;
		DeleteObject(bmDIAa) ;
		DeleteObject(bmDTLa) ;
		DeleteObject(bmNULa) ;
		DeleteObject(bmNULOa) ;
		DeleteObject(bmNULDa) ;
        DeleteObject(bmPRJOa) ;
        DeleteObject(bmLEFOa) ;
        DeleteObject(bmRYTOa) ;
		DeleteObject(bmDIAOa) ;
		DeleteObject(bmDTLOa) ;

        DeleteObject(bmLSA) ;
        DeleteObject(bmLSR) ;
        DeleteObject(bmLSG) ;
        DeleteObject(bmLSB) ;
        DeleteObject(bmLSC) ;
        DeleteObject(bmLSCO) ;
        DeleteObject(bmGRA) ;
        DeleteObject(bmGRAO) ;
        DeleteObject(bmGRY) ;
        DeleteObject(bmCLR) ;
        DeleteObject(bmSGF) ;
        DeleteObject(bmHIP) ;
        DeleteObject(bmHIPO) ;
        DeleteObject(bmHID) ;
        DeleteObject(bmLOP) ;
        DeleteObject(bmLOPO) ;
        DeleteObject(bmLOD) ;
        DeleteObject(bmCAL1) ;
        DeleteObject(bmCAL1B) ;
        DeleteObject(bmCAL1O) ;
        DeleteObject(bmCAL1D) ;
        DeleteObject(bmCAL2) ;
        DeleteObject(bmCAL2B) ;
        DeleteObject(bmCAL2O) ;
        DeleteObject(bmCAL2D) ;
        DeleteObject(bmLEV) ;
        DeleteObject(bmLEVO) ;
        DeleteObject(bmHYTN) ;
        DeleteObject(bmHYTNO) ;
        DeleteObject(bmHYTL) ;
        DeleteObject(bmHYTLO) ;
        DeleteObject(bmHYTR) ;
        DeleteObject(bmHYTRO) ;
        DeleteObject(bmHYTB) ;
        DeleteObject(bmHYTBO) ;
        DeleteObject(bmEXCLU) ;
        DeleteObject(bmEXCLO) ;
        DeleteObject(bmLSG) ;
        DeleteObject(bmBIP) ;
        DeleteObject(bmBOP) ;
		DeleteObject(bmREZ) ;
		DeleteObject(bmRZG) ;
		DeleteObject(bmREZO) ;
		DeleteObject(bmREZH) ;
		DeleteObject(bmREZD) ;
		DeleteObject(bmAUT) ;
		DeleteObject(bmAUTO) ;
		DeleteObject(bmAUTD) ;
		DeleteObject(bmALF) ;
		DeleteObject(bmALFO) ;
		DeleteObject(bmALFD) ;
		DeleteObject(bmART) ;
		DeleteObject(bmARTO) ;
		DeleteObject(bmARTD) ;
		DeleteObject(bmACP) ;
		DeleteObject(bmACPO) ;
		DeleteObject(bmPRM) ;
		DeleteObject(bmPRMO) ;
		DeleteObject(LftArrow) ;
		if(hPatch)
		DeleteObject(hPatch) ;
		if(hPatch1)
		DeleteObject(hPatch1) ;
		SetCursor(LoadCursor(NULL, IDC_ARROW)) ;
		DestroyCursor(hTarget) ;
		DestroyCursor(hTargetF) ;
		DestroyCursor(hTargetLock) ;
		DestroyCursor(hTargetLockF) ;
		DestroyCursor(hTargetW) ;
		DestroyCursor(hTargetLockW) ;
		DestroyCursor(hRotCur[1]) ;
		DestroyCursor(hRotCur[2]) ;
		DestroyCursor(hRotCur[3]) ;
		DestroyCursor(hRotCur[4]) ;
		DestroyCursor(hDpeak) ;
		DestroyCursor(hTracklftCur) ;
		DestroyCursor(hTrackrytCur) ;
        if (GlobalSize( sat)) GlobalFree(   sat ) ;
        if (GlobalSize( hue)) GlobalFree(   hue ) ;
        if (GlobalSize(dhue)) GlobalFree(  dhue ) ;
        if (GlobalSize( lum)) GlobalFree(   lum ) ;
		if (GlobalSize(dlum)) GlobalFree(  dlum ) ;
		if ( GlobalSize(Tk.Beplft)) GlobalFree( Tk.Beplft ) ;
		if ( GlobalSize(tk.Beplft)) GlobalFree( tk.Beplft ) ;
		if ( GlobalSize(Tk.Bepryt)) GlobalFree( Tk.Bepryt ) ;
		if ( GlobalSize(tk.Bepryt)) GlobalFree( tk.Bepryt ) ;
		if ( GlobalSize(Tk.Blftcapt)) GlobalFree( Tk.Blftcapt ) ;
		if ( GlobalSize(tk.Blftcapt)) GlobalFree( tk.Blftcapt ) ;
		if ( GlobalSize(Tk.Brytcapt)) GlobalFree( Tk.Brytcapt ) ;
		if ( GlobalSize(tk.Brytcapt)) GlobalFree( tk.Brytcapt ) ;

		KillTimer( hWnd,IDT_BTIMER ) ;
		KillTimer( hWnd,IDT_BTIMER1) ;

		return 0L ;
		break ;

        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
     }

    return ((long)NULL) ;

} //End of BudWndProc

int FreeTrackMemory( LPTRKINFO trk ) 
{
	int success ;

	TRKINFO t ;
	t = *trk ;
	success = 1 ; // presume all OK

  // free up any already-used memory: if any failure, cancel success
     if (t.Beplft != NULL)
	 {if ((GlobalFree(t.Beplft)) != NULL)   success = 0 ;}
     if (t.Bepryt != NULL)
	 {if ((GlobalFree(t.Bepryt)) != NULL)   success = 0 ;}
	 if (t.Blftcapt != NULL)
	 {if ((GlobalFree(t.Blftcapt)) != NULL) success = 0 ;}
	 if (t.Brytcapt != NULL)
	 {if ((GlobalFree(t.Brytcapt)) != NULL) success = 0 ;}

	 t.Brytloidx = t.Blftloidx = 0 ;
	 t.Brythiidx = t.Blfthiidx = hs ; 
	 t.Brcapt = t.Blcapt = 0 ;
	 
	 if (!success)
		 MessageBox(NULL, "Failed.", "Free Track Memory", MB_OK) ;

	     return success ;
}

void AllocTrackHyts(LPTRKINFO trk, int hs )
{
	int i ;

  // allocate arrays for the maxima position indices
  // and for the captured edge peaks.

	 trk->Beplft   = (int *)GlobalAlloc(GPTR, hs * sizeof(int)) ;
	 trk->Bepryt   = (int *)GlobalAlloc(GPTR, hs * sizeof(int)) ;
	 trk->Blftcapt = (int *)GlobalAlloc(GPTR, hs * sizeof(int)) ;
	 trk->Brytcapt = (int *)GlobalAlloc(GPTR, hs * sizeof(int)) ;

	 if (
		 trk->Beplft   == (int *)NULL ||
		 trk->Bepryt   == (int *)NULL ||
		 trk->Blftcapt == (int *)NULL ||
		 trk->Brytcapt == (int *)NULL
		   ){ msgbox = 1 ;
		 MessageBox( NULL,
		            "Tracking Allocations Failed",
					"Tracking",
					 MB_OK
					) ; msgbox = 0 ;
	                return ; }

  // fill with -2 to indicate unused element

	 for (i = 0 ; i < hs ; i++) trk->Beplft[i] = trk->Bepryt[i] = -2 ;

 // initialise the Hi and Lo indices

		trk->Brythiidx = hs ;  trk->Brytloidx = 0  ;
	    trk->Blfthiidx = hs ;  trk->Blftloidx = 0  ;
}

int LinkTrackPoints( LPTRKINFO trk, int side )
{
	static int i, loidx , hiidx, * ptr, * link ;
	int count ;

	switch( side )
	{
	case LEFT:
		                loidx = trk->Blftloidx ;
	                    hiidx = trk->Blfthiidx ;
					      ptr = trk->Beplft ;
						 link = trk->Blftcapt ;
	    break ;

	case RIGHT:         
		                loidx = trk->Brytloidx ;
	                    hiidx = trk->Brythiidx ;
					      ptr = trk->Bepryt ;
						 link = trk->Brytcapt ;
		break ;
	}

	for ( i = loidx,  count = 0 ; i <= hiidx ; i++ )
		if (ptr[i] >= 0) link[count++] = i ;

	return ( count ) ;
}

/************  Not in use, but may be, one day  ******************

BOOL StandardBud( void )
{
	       int i, idx ;
 static double h, x, oh, ox, dx, dy ;

 // lcapt, rcapt are the numbers's of captured edge points.

 // lftcapt[], rytcapt[] contain the indices of the captured edge points
 // which are also the line indices of the bud-window image, reckoned from
 // the bottom of the image, so they are the distances of the CEP's
 // in actual pixels from the image bottom.

 // autoleft[], autoryt[] contain the distances in actual pixels to the 
 // CEP's from the left of the bud-window image.
 
 // on completion of this function, lperimeter, rperimeter hold the 
 // actual perimeters in pixels between 1st and final points.
 
 // lslope[N], rslope[N] contain the slopes of segments N.

	if (autotracked)
	{
		lperim[0] = rperim[0] = 0.0 ;
		lslope[0] = rslope[0] = 0.0 ;
		licept[0] = ricept[0] = 0.0 ;

		for ( i = 1, lperimeter = 0.0 ; i <= lcapt ; i++ )
		{
			  if (i == 1)
			  {
				  oh = (double)lftcapt[0] ; // 1st CEP index
				  ox = (double)autoleft[lftcapt[0]] ; // 1st dist fm. left
			  }
			idx = lftcapt[i] ;				  // index of capture
			  h = (double)idx ;               // from bottom in pixels
			  x = (double)autoleft[idx] ;	  // from left in pixels
			 dy = h - oh ;					  // vertical step in pixels
			 dx = x - ox ;					  // horizontal step in pixels
	lperimeter += sqrt(dx*dx + dy*dy) ;		  // total perimeter thus far
      lperim[i] = lperimeter ; 				  // perimeter incl. this seg.
        if (dx != 0.0)					      // trap div. by zero			
  	  lslope[i] = dy / dx ;					  // slope of this segment
        else
	  lslope[i] =  dy * 1.0e20 ;			  // use huge signed number
      licept[i] = h - x * lslope[i] ;  		  // intercept of segment
			 oh = h ;						  // hold as old for next
			 ox = x ;
		}

		for ( i = 1, rperimeter = 0.0 ; i <= rcapt ; i++ )
		{
			  if (i == 1)
			  { 
				  oh = (double)rytcapt[0] ;
				  ox = (double)autoryt[rytcapt[0]] ;
			  }
			idx = rytcapt[i] ;
			  h = (double)idx ;
			  x = (double)autoryt[idx] ;
			 dy = h - oh ;
			 dx = x - ox ;
	rperimeter += sqrt(dx*dx + dy*dy) ;
      rperim[i] = rperimeter ;
        if (dx != 0.0)					      // trap div. by zero			
  	  rslope[i] = dy / dx ;					  // slope of this segment
        else
	  rslope[i] =  dy * 1.0e20 ;			  // use huge signed number
      ricept[i] = h - x * rslope[i] ;  

			 oh = h ;
			 ox = x ;
		}
		return (TRUE) ;
	}
	else
		return (FALSE) ;
}
**********************************************************/

BOOL MeasureTrackedBud( TRKINFO Trk )
{
	LPMEASURE M ;	  // Dimension data
 LPBUDRESULTS B ;	  // General data
      POINT Bf ;      // for conversion from RGB buffer pixels to screen pixels
	  POINT client ;  // for conversion from screen pixels to image units
	 DPOINT image ;	  // for conversion from screen pixels to image units
	    int i, j ;
		int idx ; // index of a CEP = height in pixels from image bottom
	 double dx ;  // x increment
	 double dy ;  // y increment
	 double ml ;  // slope of measuring level 
     double cl ;  // intercept of measuring level in image units
	 double ms ;  // slope of segment
	 double cs ;  // intercept of segment in image units
	 double xa ;  // x of an axis level-cut
	 double ya ;  // y of an axis level-cut
	 double x1  ; // x of lower segment point in image units
	 double y1  ; // y of lower segment point in image units
	 double x2  ; // x of upper segment point in image units
	 double y2  ; // y of upper segment point in image units
	 double xc ;  // x intersect of level with segment
	 double yc ;  // y intersect of level with segment
	 TRKINFO t ;

	 t = Tk ;
 // for all units, the origin is the bottom left of the image

	if (autotracked)
	{
		ResetMeasure(hWndBud, LEV, EdgeDone) ;
		M = pMeasure ;
		B = pBudResults ;
		toArchive = 1 ;

		// run up through all measure levels
		for ( i = 1 ; i <= Levels ; i++ )
		{
	        // details of the measure levels
		    // in Image Units (i.u.)

			xa = M->iAxisCuts[i].x ;	   // cutting point of Level..  
			ya = M->iAxisCuts[i].y ;	   // ..with Inter-Pole axis
			ml = M->iLevGradIcepts[i].x ;  // slope
			cl = M->iLevGradIcepts[i].y ;  // intercept
			
			// run up the segments of the left profile
			// until the segment intersected by the
			// measure level is found.

			for (j = 1 ; j <= t.Blcapt ; j++)
			{
			// the lower of the segment's end points

				 idx = t.Blftcapt[j - 1] ;
				Bf.y = hs - idx ;
				Bf.x = t.Beplft[idx] ;
			    InsetToCli(&client, &Bf) ;

			    CliToImg(&image, &client) ;

        	       x1 = image.x ;	  // x of CEP in i.u
				   y1 = image.y ;	  // y of CEP in i.u.

		   // the upper of the segment's end points

				 idx = t.Blftcapt[j] ;
				Bf.y = hs - idx ;
				Bf.x = t.Beplft[idx] ;
			    InsetToCli(&client, &Bf) ;

			    CliToImg(&image, &client) ;

    		      x2 = image.x ;	  // x of CEP in i.u.
			      y2 = image.y ;	  // y of CEP in i.u.

			// slope
				   dx = x2 - x1 ;
				   dy = y2 - y1 ;
				   if (dx != 0.0)
				   ms = dy / dx ;
				   else
				   ms = dy * 1.0e20 ;

			// N.B.  ???need to detect special cases???
				   cs = y2 - ms * x2 ;  // intercept of segment in i.u.

			// intersection of level with segment
				   xc = (cs - cl) / (ml - ms) ; // x of intersection
				   yc = ml * xc + cl ;			// y of intersection

			// check if the intersection lies in-segment
				if (y1 <= yc && yc <= y2)
				{
					M->iLeftCut[i].x = xc ;
					M->iLeftCut[i].y = yc ;
					M->iLeftRad[i] = sqrt(pow(xa-xc,2.0)+pow(ya-yc,2.0)) ;
					Construct( i, LEFT ) ;
					RecordDimensions() ;
					   SomeDone = set ;
					LEdgeOrg[i] = TRACKED ;
				    ivrc(hWndBud,&rclv[Levels - i],FALSE) ;
					break ;
				}
			}

			// Do the right profile
			for (j = 1 ; j <= t.Brcapt ; j++)
			{
				 idx = t.Brytcapt[j - 1] ;
				Bf.y = hs - idx ;
				Bf.x = t.Bepryt[idx] ;
				InsetToCli(&client, &Bf) ;

			    CliToImg(&image, &client) ;

    		      x1 = image.x ;
				  y1 = image.y ;

				 idx = t.Brytcapt[j] ;
				Bf.y = hs - idx ;
				Bf.x = t.Bepryt[idx] ;
				InsetToCli(&client, &Bf) ;

			    CliToImg(&image, &client) ;

    		      x2 = image.x ;	  // x of CEP in i.u.
			      y2 = image.y ;	  // y of CEP in i.u.

			// slope
				   dx = x2 - x1 ;
				   dy = y2 - y1 ;
				   if (dx != 0.0)
				   ms = dy / dx ;
				   else
				   ms = dy * 1.0e20 ;

			// N.B.  need to detect special cases
				   cs = y2 - ms * x2 ;  // intercept of segment in i.u.

			// intersect of level with segment
				   xc = (cs - cl) / (ml - ms) ; // x of intersect
				   yc = ml * xc + cl ;			// y of intersect

			// check if the intersect lies in-segment
				if (y1 <= yc && yc <= y2)
				{
					M->iRightCut[i].x = xc ;
					M->iRightCut[i].y = yc ;
					M->iRightRad[i] = sqrt(pow(xa-xc,2.0)+pow(ya-yc,2.0)) ;
					Construct( i, RIGHT ) ;
					RecordDimensions() ;
					   SomeDone = set ;
					REdgeOrg[i] = TRACKED ;
				    ivrc(hWndBud,&rclv[Levels - i],FALSE) ;
					break ;
				}
			}
		}

		  ivrc(hWndRslt,&rcrslt,TRUE) ;

		  // check for all levels measured: first assume they are,
		  // then if one found which isn't, reset AllDone flag.
				   for (i = 1, AllDone = 1; i <= Levels ; i++)
					   if (EdgeDone[i] != BOTH) AllDone = 0 ;

                   if (AllDone)
				   {
					   Lambda(LEFT) ;
					   Lambda(RIGHT) ;
					   Lambda(BOTH) ;
					   RecordLambdas() ;
					TrialLam = PRJ ? pBudResults->DiamProjLambda : pBudResults->DiamRegrLambda ;
				    TrialRad = 0.5 * M->iDiameter[(Levels+1)/2] ;
				   }

		return (TRUE) ;
	}
	else
		return (FALSE) ;
}

// Conversions

void CliToBuff(POINT * B, POINT * S)
// Accepts client co-ordinates, origin TLC of client
// Returns buffer co-ordinates, origin TLC of buffer.
{
	B->x = MulDiv(S->x - rcimg.left, ws, bimwid) + xsa ;
	B->y = MulDiv(S->y - rcimg.top,  hs, bimhyt) + ysa ;
}

void BuffToCli(POINT * S, POINT * B)
// Accepts buffer co-ordinates, origin TLC of buffer
// Returns client co-ordinates, origin TLC of client
{
	S->x = MulDiv(B->x - xsa, bimwid, ws) + rcimg.left ; 
	S->y = MulDiv(B->y - ysa, bimhyt, hs) + rcimg.top ;
}

void CliToInset(POINT * B, POINT * S)
// Accepts client co-ordinates,          origin TLC of client.
// Returns co-ordinates in buffer inset, origin TLC of buffer inset
{
	B->x = MulDiv(S->x - rcimg.left, ws, bimwid) ;
	B->y = MulDiv(S->y - rcimg.top,  hs, bimhyt) ;
}

void InsetToCli(POINT * S, POINT * B)
// Accepts buffer inset co-ordinates, origin TLC of buffer inset
// Returns client co-ordinates,       origin TLC of client
{
	S->x = MulDiv(B->x, bimwid, ws) + rcimg.left ; 
	S->y = MulDiv(B->y, bimhyt, hs) + rcimg.top ;
}

void BuffToImg(DPOINT * I, POINT * B)
// Accepts buffer co-ordinates, origin TLC of buffer
// Returns image co-ordinates,  origin BLC of image
{
	POINT S ;
	BuffToCli(&S, B) ;
	 CliToImg(I, &S) ;
}

void ImgToBuff(POINT * B, DPOINT * I)
// Accepts image co-ordinates,  origin BLC of image
// Returns buffer co-ordinates, origin TLC of buffer
{
	POINT S ;
	 ImgToCli(&S, I) ;
	CliToBuff(B, &S) ;
}

void InsetToImg(DPOINT * I, POINT * B)
// Accepts buffer inset co-ordinates, origin TLC of buffer
// Returns image co-ordinates,  origin BLC of image
{
	POINT S ;
	InsetToCli(&S, B) ;
	  CliToImg(I, &S) ;
}

void ImgToInset(POINT * B, DPOINT * I)
// Accepts image co-ordinates,  origin BLC of image
// Returns buffer co-ordinates, origin TLC of buffer
{
	POINT S ;
	  ImgToCli(&S, I) ;
	CliToInset(B, &S) ;
}

void Construct(int L, int Side)
{
	   LPMEASURE M ;
	LPBUDRESULTS B ;

	M = pMeasure ;
	B = pBudResults ;

	          if (Side == LEFT)
	             {
				   switch(EdgeDone[L])
				   {
				   case NONE:
				   // if none yet done, this must be a left edge

					   pBudResults->Edges[L] = EdgeDone[L] = LEFT ;

					   break ;

				   case RIGHT:
				   // if right already done, and we are doing the left
				   // this must mean both now done,
				   // so we can now get the diameter, and mid point.

					   pBudResults->Edges[L] = EdgeDone[L] = BOTH ;

					   goto getdiamids ;

				       break ;

				   case BOTH :
					   // if both already done, this must be an
					   // adjustment of the left radius, so we
					   // should recalculate the diameter and mid point.

					   goto getdiamids ;

					   break ;

				   default:
					   break ;
				   }
			   }
			   else // we are to the right of the interpole line
			   {

				   switch(EdgeDone[L])
				   {
				   case NONE:
				   // if none yet done, this must be a right edge

					   pBudResults->Edges[L] = EdgeDone[L] = RIGHT ;

					   break ;

				   case LEFT:
					   // if left already done, and we doing the right,
					   // this must mean both now done,
					   // so we can now get the diameter, and mid point.

					   pBudResults->Edges[L] = EdgeDone[L] = BOTH ;

					   goto getdiamids ;

					   break ;

				   case BOTH:
					   // if both already done, this must be an
					   // adjustment of the right radius, so we
					   // should recalculate the diameter and mid point.

getdiamids:		   M->iDiameter[L] = M->iLeftRad[L] + M->iRightRad[L] ;
				        MidPt[L].x = ( M->iLeftCut[L].x +
							           M->iRightCut[L].x ) / 2.0 ;
				        MidPt[L].y = ( M->iLeftCut[L].y +
							           M->iRightCut[L].y ) / 2.0 ;
		AxisRadius[L] = sqrt(pow(M->iAxisCuts[L].x - MidPt[L].x, 2.0) +
						     pow(M->iAxisCuts[L].y - MidPt[L].y, 2.0));

		if (MidPt[L].x < M->iAxisCuts[L].x) AxisRadius[L] *= -1.0 ;

					   break ;

				   default:
					   break ;
				   }
			   }
}

void ResetCalibration( void )
{
			  calibrated = reset ;
			 calibrating = reset ;
	   CAL1SET = CAL2SET = reset ;
	             SETCAL1 =   set ;
			       Units = IMAGEUNITS ;
				 CalSize = 0.0 ;

	ivrc(hWndBud, NULL, TRUE) ;
	  UpdateWindow(hWndBud) ;
	ivrc(hWndRslt, NULL, TRUE) ;
	  UpdateWindow(hWndRslt) ;
}

void ResetMeasure( HWND hWnd, int LEV[], int EdgeDone[] )
{
	int i, button ;
			 // redisplay the button column
			 // init all to unselected state
		     // and set status of each level to
			 // 'neither edge measured' (NONE)
			 // set all measurements to zero.
				for ( i = 1 ; i <= Levels ; i++ )
			    {
					pMeasure->iLeftRad[i]  = 0.0 ;
					pMeasure->iRightRad[i] = 0.0 ;
					pMeasure->iDiameter[i] = 0.0 ;	
					button = Levels - i ;
				 LEV[button] = btn_up ;			 
				 ivrc(hWnd,&rclv[button],FALSE) ;
				 EdgeDone[i] = LEdgeOrg[i] = REdgeOrg[i] = NONE ;
			    }
			 // say no level is selected
				AllDone = SomeDone = 0 ;
			 // remove level-locking if any
			 	 Locked = JustLocked = reset ;
		     // tell measurement about change
				 MeasureGrid(pMeasure) ;
}

/****************************
  Pop up information window
 ****************************/
long CALLBACK  OverlayProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
					   
	switch(message)
	{

	case WM_COMMAND:

		switch (LOWORD(wParam))
		{
	case WM_MOUSEGONE:  // mouse has gone from THIS window
		// get rid of any tip showing
		   if (CurrentTip != (HWND)NULL)
		   RemoveTip() ;
		   return 0L ;

	default: break ;
		}
		break ;

 	// might as well use this, as there is nothing but client area.
	case WM_MOUSEMOVE:
	if (hWnd != CurrentWindow) // mouse has moved into THIS window
	{
		// tell the abandoned window it's gone
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		// establish this window as current mouse window 
		CurrentWindow = hWnd ;
	}
		break ;
 
        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
	}
 return ((long)NULL) ;
}


//***************************************
//		Geo-Location by GPS
//***************************************
BOOL CALLBACK GPSDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	int snafu, i ;
	static   connect = 0 ;
	static connected = 0 ;
	static      test = 0 ;
	static char com[10], str[10] ;
	static char *baud[] = {"4800", "9600", "38400"} ;

	switch(msg)
	{

		case WM_INITDIALOG:
		SendDlgItemMessage(hDlg, IDC_GPS_SELCOMMPORT, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCTSTR)"COM3") ;
		
		for (i = 1 ; i <= 9 ; i++)						// fill the COM list
		{
	    strcpy(com, "COM") ;
		strcat(com, _itoa(i, str, 10)) ;
		PutInCombo(hDlg, IDC_GPS_SELCOMMPORT, com) ;
		}

		SendDlgItemMessage(hDlg, IDC_GPS_SELBAUDRATE, WM_SETTEXT, (WPARAM)0, (LPARAM)(LPCTSTR)"38400") ;

		for (i = 0 ; i < 3 ; i++)						// fill the Baud list
		PutInCombo(hDlg, IDC_GPS_SELBAUDRATE, baud[i]) ;

		SetDlgItemText(hDlg, IDC_CONNECT_STATE, "GPS is off") ;
		SetDlgItemText(hDlg, IDC_GPS_GOOD, "None") ;

			return TRUE ;

		case WM_COMMAND:

		switch (LOWORD(wParam)) // pick up edit-box notifications
		{
			case IDC_GPS_SELCOMMPORT:
				GetDlgItemText(hDlg, IDC_GPS_SELCOMMPORT, port, 20) ;
				break;

			case IDC_GPS_SELBAUDRATE:
				baudrate = GetDlgItemInt(hDlg, IDC_GPS_SELBAUDRATE, &snafu, FALSE) ;
				break;

			case IDC_GPS_CONNECT:

				connect ^= 1 ;
				if (connect)
				{
					char str[]="Could not find GPS.\nIs it plugged in?";
					if(!CreateGPSPort(port, baudrate))
					{
						MessageBox(NULL, str, "", MB_OK) ;
						return FALSE;
					}
					else //is connected, enable testing, allow disconnection
					{
						EnableWindow(GetDlgItem(hDlg,IDC_GPS_TEST), TRUE) ;
						SetDlgItemText(hDlg, IDC_GPS_CONNECT, "Disconnect GPS") ;
						SetDlgItemText(hDlg, IDC_CONNECT_STATE, "GPS is on") ;
						connected = 1 ;
					}
				}
				else
				if (hGPSCom != NULL)// if we have a valid handle, try to close it
				{
					if (!CloseHandle(hGPSCom))
						MessageBox(NULL,"GPS COM port did not close.", "", MB_OK) ;
					else //ok, is disconnected, disable testing, allow reconnection
					{
						EnableWindow(GetDlgItem(hDlg,IDC_GPS_TEST), FALSE) ;
						SetDlgItemText(hDlg, IDC_GPS_CONNECT, "Connect GPS") ;
						SetDlgItemText(hDlg, IDC_CONNECT_STATE, "GPS is off") ;
						SetDlgItemText(hDlg, IDC_GPS_GOOD,"None") ;
						connected = 0 ;
					}
				}
				break ;

			case IDC_GPS_TEST:
				{
					int i, j, k, m, len ;
					double n, u ;
					char T1[20], T2[20], T3[20] ;
					static char * Words[16] ;

					  for (i = 0 ; i < 16 ;		// allocate a few words
	  Words[i++] = (char *)GlobalAlloc(GPTR, 16 * sizeof(char))) ;

retry:				GPSstring[0] = '\0' ;
					dwSize = 0 ;

					if (!WaitCommEvent(hGPSCom, &dwCommEvent, NULL))
					{
					// An error occurred waiting for the event.
						MessageBox(NULL, "We have a Comm error", "", MB_OK);
						goto get_out ;
					}
					 else	// Event has occurred (a char is in the buffer).
					 {
						 DWORD dwRead ;
						 char b ;
						 do
						 {
							if(ReadFile(hGPSCom, &b, 1, &dwRead, NULL) != 0)
							{
								if(dwRead > 0)
								{
									GPSstring[dwSize] = b ;
									dwSize += dwRead ;
								}
							} else break ;
						 } while (dwRead > 0 && b != 10) ;	// a line feed ends an NMEA sentence

						 GPSstring[dwSize] = '\0' ;			// terminate the NMEA string

						 if(strstr(GPSstring, "$GPRMC") == (char *)NULL)	// is this not the one we want?
								goto retry ;								// not the one, keep looking
						 SetDlgItemText(hDlg, IDC_GPS_WORD, GPSstring) ;	// it's the one, put it in the top edit box
					}  // drop through on success

					// parse the comma-separated NMEA string into words
					len = strlen(GPSstring) ;
					for (i = 0, j = 0, k = 0 ; i < len ; i++)
					{
						if (GPSstring[i] == ',')	// on comma start new word
						{j++ ; i++, k = 0 ;}		// (i++ to skip the comma)
							*(Words[j] + k++) = GPSstring[i] ;
					}
					
					if (!strcmp(Words[2],"A")) 
						SetDlgItemText(hDlg, IDC_GPS_GOOD, "HIGH") ;
					else
						SetDlgItemText(hDlg, IDC_GPS_GOOD, "BAD!" ) ;
					

					strcpy(T1, Words[3]) ; len = strlen(T1) ;						// entire GPS latitude string
					for (i = 0 ; i < 2 ; GPSlat[i] = T1[i++]) ; GPSlat[i] = '\0' ;	// break out degrees as string
					strcat(GPSlat, "°  ") ;											// annotate
					for (i = 2 ; i < len; T2[i - 2] = T1[i++]); T2[i-2] = '\0' ;	// break out minutes as string
					n = atof(T2) ;			// convert string minutes to float
					u = n - (m = (int)n);	// m is whole minutes, u is fraction of minute
					u *= 60.0 ;				// convert fraction to seconds and decimal seconds
					sprintf(T3, "%d", m) ;	// whole minutes
					sprintf(T2, "%5.3f",u);	// seconds and fraction of second as string
					strcat(GPSlat, T3) ; strcat(GPSlat, "'  ") ; 
					strcat(GPSlat, T2) ; strcat(GPSlat, "\"  ");
					strcat(GPSlat, Words[4]) ;
					SetDlgItemText(hDlg, IDC_GPS_LAT,  GPSlat ) ; // to edit box

					strcpy(T1,Words[5]) ; len = strlen(T1) ;						// entire GPS longitude string
					for (i = 0 ; i < 3 ; GPSlong[i] = T1[i++]) ; GPSlong[i] = '\0' ;
					strcat(GPSlong,"°  ") ;
					for (i = 3 ; i < len; T2[i-3] = T1[i++]); T2[i-3]= '\0' ;
					n = atof(T2) ;
					u = n - (m = (int)n) ;	// m is whole minutes, u is fraction of minutes
					u *= 60.0 ;				// convert fraction to seconds and decimal seconds
					sprintf(T3,"%d", m) ;	// minutes
					sprintf(T2, "%5.3f",u);
					strcat(GPSlong, T3) ; strcat(GPSlong, "'  ") ;
					strcat(GPSlong, T2) ; strcat(GPSlong, "\"  ") ;
					strcat(GPSlong,  Words[6]) ;
					SetDlgItemText(hDlg, IDC_GPS_LONG, GPSlong) ;

get_out:					for (i = 0 ; i < 16 ; GlobalFree(Words[i++])) ; // free allocated
				}
				break ;
			}
			break ; // end case WM_COMMAND:
	}	// end switch (msg)

		return FALSE ;
}

//**********************************************
//  Create and Configure a serial port for GPS
//**********************************************
BOOL CreateGPSPort(char * port, int baudrate)
// The COM number & baudrate
// need to be specified per
// machine and GPS device.
{
   DCB dcb;
 DWORD dwError;
  BOOL fSuccess;

	hGPSCom = CreateFile( port,
		GENERIC_READ | GENERIC_WRITE,
		0,				// comm devices must be opened w/exclusive-access 
		NULL,			// no security attributes 
		OPEN_EXISTING,	// comm devices must use OPEN_EXISTING 
		0,				// not overlapped I/O 
		NULL			// hTemplate must be NULL for comm devices 
		);

	if (hGPSCom == INVALID_HANDLE_VALUE) 
	{
		dwError = GetLastError();

		// handle error
		MessageBox(NULL,"No Comm Handle","",MB_OK) ;
		return FALSE ;
	}

// Omit the call to SetupComm to use the default queue sizes.
// Get the current configuration.

	fSuccess = GetCommState(hGPSCom, &dcb);

	if (!fSuccess) 
	{
    // Handle the error.
	MessageBox(NULL,"No Get Comm State","",MB_OK) ;
	return FALSE ;
	}

// If this were for the ND-100 GPS usb dongle, we would
// fill in the DCB thus : baud=38400, 8 data bits, no parity, 1 stop bit.
// Only the COM # and baudrate are adjustable.
// The others are specified by the GPS "NMEA" standard (I think!).  

	dcb.BaudRate = baudrate ;
	dcb.ByteSize = 8;
	dcb.Parity   = NOPARITY;
	dcb.StopBits = ONESTOPBIT;

	fSuccess = SetCommState(hGPSCom, &dcb);

	if (!fSuccess) 
	{
    // Handle the error.
	MessageBox(NULL,"No Set Comm State","",MB_OK) ;
	return FALSE;
	}

	if (!SetCommMask(hGPSCom, dwStoredFlags))
	{
	MessageBox(NULL, "No Stored Event Flags", "", MB_OK) ;
	return FALSE ;
	}

		return TRUE ;  //Everything should be ready to go now

}	// CreateGPSPort()

// ********************************
//		Use the GPS
// ********************************

void GetGps( void ) //TO DO
{
	;
}	// GetGps()

/*******************************************************************

                 Window Procedure for Results

 *******************************************************************/
long CALLBACK  ResultsProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
   PAINTSTRUCT ps ;
           HDC hdc, hmemDC ;
		BITMAP bm ;
	   HBITMAP hBm, OBm ;
		 HFONT oFnt ;
		  HPEN oPen ;
   static SIZE sz ;
  static POINT pt, Sc, Bf ;
  static POINT box, cpt, cupt, tpt ;
  LPBUDRESULTS B ;
     LPMEASURE M ;
    static TXT T ;
	static char * unit[] = {"in","mm","iu" } ;
	static display = 0 ;
	    double rwid, mult ;
   static char buff[150], * titleptr ;

		static Btn, Btn1 ;
		static i, s, px, py, px1, py1, px2, py2 ;
		static idx, PixCol ;

	switch(message)
	{
	case WM_COMMAND:
		switch (LOWORD(wParam))
		{
		case WM_MOUSEGONE:
		   if (CurrentTip != (HWND)NULL)
		   RemoveTip() ;
		   return 0L ;

		case SEL_LAMBDA_DIA:		//CTRL+SHIFT+D
		RYT = LEF = 0 ; DIA ^= 1 ; 

		if (!(DIA || LEF || RYT) && NPR) // if DIA turned off
			SendMessage(hWnd,WM_COMMAND,SEL_NULL_PROFILE,0L) ;
		
		if (DIA)
		{ 
			if (shownullgraph)
			{
				Lambda(BOTH) ;
				ivrc(hWndNPGraf,NULL,TRUE) ;
			}
		}
		ivrc(hWnd,&rcrslt,TRUE) ;
		UpdateWindow(hWnd) ;
			break ;

		case SEL_LAMBDA_LEF:		//CTRL+SHIFT+L
		DIA = RYT = 0 ; LEF ^= 1 ; 

		if (!(DIA || LEF || RYT) && NPR) // if LEF is turned off
			SendMessage(hWnd,WM_COMMAND,SEL_NULL_PROFILE,0L) ;
		
		if (LEF)
		{ 
			if (shownullgraph)
			{
				Lambda(LEFT);
				ivrc(hWndNPGraf,NULL,TRUE) ;
			}
		}
		ivrc(hWnd,&rcrslt,TRUE) ;
		UpdateWindow(hWnd) ;
			break ;

		case SEL_LAMBDA_RYT:	    //CTRL+SHIFT+R
		DIA = LEF = 0 ; RYT ^= 1 ; 

		if (!(DIA || LEF || RYT) && NPR) // if RYT is turned off
			SendMessage(hWnd,WM_COMMAND,SEL_NULL_PROFILE,0L) ;
		
		if (RYT)
		{
			if (shownullgraph) 
			{
				Lambda(RIGHT) ;
				ivrc(hWndNPGraf,NULL,TRUE) ;
			}
		}
		ivrc(hWnd,&rcrslt,TRUE) ;
		UpdateWindow(hWnd) ;
		    break ;

		case SEL_LAMBDA_TYP:        //CTRL+SHIFT+T
		PRJ ^= 1 ;
		ivrc(hWnd,&rcrslt,TRUE) ;
		UpdateWindow(hWnd) ;
			break ;

		case SEL_NULL_PROFILE:

			if (!(DIA || LEF || RYT)) // if no selection, prevent display
			NPR = 0 ;
			else					  // otherwise, toggle display
			NPR ^= 1 ;

		// shownullgraph is redundant: the display flag NPR could do its job,
		// but we retain it to keep our intentions clear!

		// Actually, on second thoughts, it isn't! NPR is not a global.

			shownullgraph = NPR ;

		    ivrc(hWnd,&rctl[Npr],TRUE) ;

			if (shownullgraph)       // ensure that data is available
			{
			if (DIA)
				Lambda(BOTH) ;
			if (LEF)
				Lambda(LEFT) ;
			if (RYT)
				Lambda(RIGHT) ;

			    ShowWindow(hWndNPGraf, SW_SHOW) ;
				SetWindowPos(hWndNPGraf, HWND_TOP,
					         0,0,0,0,
							 SWP_NOSIZE|SWP_NOMOVE) ;
				ivrc(hWndNPGraf,NULL,TRUE) ;
			}
			else
			ShowWindow(hWndNPGraf, SW_HIDE) ;
			break ;

		default : break ;
		}
		break ;

	case WM_RESET: // On new file, re-size or re-pole

		RYT = LEF = display = 0 ;
		PRJ = 1 ; DIA = 1 ;
		showImage = 1 ;
		showGrid  = 1 ;
		showAnnot = 1 ;
		showTrack = 1 ;
		break ;

	case WM_RBUTTONDOWN:
		
		if (++display > 10 ) display = 0 ;

		switch(display)
		{
	case 0: showImage = 1 ; showGrid = 1 ; showAnnot = 1 ; showTrack = 1 ; 
			break ;	  //+I+G+A+T
  	case 1:	showImage = 1 ; showGrid = 1 ; showAnnot = 0 ; showTrack = 1 ;
			break ;	  //+I+G-A+T
	case 2:	showImage = 0 ; showGrid = 1 ; showAnnot = 0 ; showTrack = 1 ;
			break ;	  //-I+G-A+T
	case 3: showImage = 0 ; showGrid = 1 ; showAnnot = 1 ; showTrack = 1 ;
			break ;	  //-I+G+A+T
	case 4:	showImage = 1 ; showGrid = 0 ; showAnnot = 0 ; showTrack = 1 ;
			break ;	  //+I-G-A+T
	case 5:	if (!autotracked) break ;
		    showImage = 0 ; showGrid = 0 ; showAnnot = 0 ; showTrack = 1 ;
			break ;	  //-I-G-A+T

	case 6: showImage = 1 ; showGrid = 1 ; showAnnot = 1 ; showTrack = 0 ; 
			break ;	  //+I+G+A-T
  	case 7:	showImage = 1 ; showGrid = 1 ; showAnnot = 0 ; showTrack = 0 ;
			break ;	  //+I+G-A-T
	case 8:	showImage = 0 ; showGrid = 1 ; showAnnot = 0 ; showTrack = 0 ;
			break ;	  //-I+G-A-T
	case 9: showImage = 0 ; showGrid = 1 ; showAnnot = 1 ; showTrack = 0 ;
			break ;	  //-I+G+A-T
	case 10:showImage = 1 ; showGrid = 0 ; showAnnot = 0 ; showTrack = 0 ;
			break ;	  //+I-G-A-T
		}

		ivrc(hWnd,NULL,TRUE) ;
		UpdateWindow(hWnd) ;
		break ;

	case WM_TIMER:
			switch(wParam)
			{
			case IDT_VOCTIMER:
			GetCursorPos(&cupt) ;
			ScreenToClient(hWnd,&cupt) ;
			if (PtInRect(&rctl[UseBtn],cupt))
			{
				if (UseBtn == Prj)
				{
					if (PRJ)
					PlaySound("regresult.wav", NULL, SND_ASYNC) ;
					else
					PlaySound("prjresult.wav", NULL, SND_ASYNC) ;
				}
				else
				PlaySound(szVocTipWav[UseBtn], NULL, SND_ASYNC) ;
			}
			KillTimer(hWnd,VTim) ;
			break ;

			case IDT_TIPDWELL:
			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 DestroyWindow(hWndInfo[UseCtl]) ;
				 CurrentTip = (HWND)NULL ;
				 hWndOfCurrentTip = (HWND)NULL ;
			 }
			 KillTimer(hWnd, IDT_TIPDWELL) ;
			 Dwelling[UseCtl] = 0 ;
				return 0L ;

			case IDT_TIPDEFER:
			 KillTimer(hWnd,IDT_TIPDEFER) ;
			 Deferred[UseCtl] = 0 ;
			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseCtl],cupt))
				PutTip(hWnd, 0, 3) ;
			    break ;

			default:
				break ;
			}
			return 0L ;
		break ;

   	case WM_NCHITTEST: // works for any mouse event in this window
	if (hWnd != CurrentWindow) // If this window isn't current
	{
		// Tell abandoned window that the rodent has left
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		// Establish this window as the rodent's current window
		CurrentWindow = hWnd ;
	}
	// The hit test must be passed to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

	case WM_MOUSEMOVE:
		{
			   HDC hdc1 ;
			static OldPicked ;
			static w, h, x, y, ox, oy ;
			static Icon1Drawn ;

		pt.x = LOWORD(lParam) ;
		pt.y = HIWORD(lParam) ;

		if (gotimage && showtips)
		{
		GetCursorPos(&cpt) ;
		ScreenToClient(hWnd,&cpt) ;
		GetTip( hWnd, AllDone ? Prj : Dtl, Dtl, cpt ) ;
		if (sounds)
			if (AllDone)
			GetVoc(hWnd,Prj,Dtl,cpt);
		    else
			GetVoc(hWnd,Dtl,Dtl,cpt) ;
		}
		if (SomeDone) // poll levels for mouse presence
		for ( i = 1, LevelPicked = 0 ; i <= Levels ; i++ )
		{
			if (PtInRect(&rcmidpt[i], pt) && EdgeDone[i] == BOTH)
			{ LevelPicked = i ; break ; }
		}
		if (LevelPicked != OldPicked) // this is a mouse move: do the following only if move at a new level.
		{
			ivrc( hWndBud, &rccolrt, TRUE ) ;
			if (shownullgraph)
			{
				    x = rcNull[i].left + 2 ; y = rcNull[i].top  + 2 ;
				    w = h = 32 ;									// width and height of patch
				  if (hPatch2 != NULL && Icon1Drawn)				// if grabbed patch exists
				  { hPatch2 = PutPatch(hWndNPGraf, hPatch2, w, h, ox, oy) ; // replace it, so wiping the icon
					  Icon1Drawn = 0 ; }
				   hPatch2 = GrabPatch(hWndNPGraf, w, h, x + 3, y + 3) ; // grab a new patch
				   ox = x + 3 ; oy = y + 3 ;				       // record place for restoration
				   hdc1 = GetDC(hWndNPGraf) ;
				   DrawIcon(hdc1, x + 3, y + 3, icoPtr) ;		   // draw the arrow-icon on top
				   Icon1Drawn = 1 ;
				   ReleaseDC(hWndNPGraf, hdc1) ;
			} // end if (shownullgraph)
		}
		else
		if (LevelPicked == 0) // no level is selected. replace patch
		{ if (shownullgraph && hPatch2 && Icon1Drawn)
		{ hPatch2 = PutPatch(hWndNPGraf, hPatch2, 32, 32, ox,  oy ) ; Icon1Drawn = 0 ; }}
		        OldPicked = LevelPicked ; }
		break ;

	case WM_LBUTTONDOWN:

	   pt.x = LOWORD(lParam) ;
	   pt.y = HIWORD(lParam) ;
	 
	 if (gotimage && AllDone) // first 4 buttons show only when
	 {						  // all measurement completed

	   if (PtInRect(&rctl[Dia],pt))				  //on Diameters
	   {
           Clicked[Dia] = 1 ;
		   KillTip(hWnd, Dia) ;
		   SendMessage(hWnd, WM_COMMAND, SEL_LAMBDA_DIA, 0L) ;
	   }

	   if (PtInRect(&rctl[Prj],pt))				  // Proj or Regr
	   {
           Clicked[Prj] = 1 ;
		   KillTip(hWnd, Prj) ;
		   SendMessage(hWnd, WM_COMMAND, SEL_LAMBDA_TYP, 0L) ;
	   }

	   if (PtInRect(&rctl[Lef],pt))				  // on Left radii
	   {
           Clicked[Lef] = 1 ;
		   KillTip(hWnd, Lef) ;
		   SendMessage(hWnd, WM_COMMAND, SEL_LAMBDA_LEF, 0L) ;
	   }
	
	   if (PtInRect(&rctl[Ryt],pt))				  // on Right radii
	   {
           Clicked[Ryt] = 1 ;
		   KillTip(hWnd, Ryt) ;
		   SendMessage(hWnd, WM_COMMAND, SEL_LAMBDA_RYT, 0L) ;
	   }
	 }

	  if (gotimage)	              // Detail button shows when image up
	  {
	   if (PtInRect(&rctl[Dtl],pt))
	    {
         Clicked[Dtl] = 1 ;
		 KillTip(hWnd, Dtl) ;
		 DTL ^= 1 ;
		 ivrc(hWnd,&rctl[Dtl],FALSE) ;
		 if (DTL)
		  {
			SendMessage(hWndCtrl,WM_COMMAND,IDM_SHOW_DETAILS,0L) ;
			DTL = 0 ;								// Cancel button after
		    ivrc(hWnd,&rctl[Dtl],FALSE) ;
		    UpdateWindow(hWnd) ;
		  }
	    }

	   if (AllDone && PtInRect(&rctl[Npr],pt))
	   {
           Clicked[Npr] = 1 ;
		   KillTip(hWnd, Npr) ;
		   SendMessage(hWnd, WM_COMMAND, SEL_NULL_PROFILE, 0L) ;
	   }

	  }
	   break ;

	case WM_LBUTTONUP:

	   pt.x = LOWORD(lParam) ;
	   pt.y = HIWORD(lParam) ;

	   break ;
		
	case WM_PAINT:
		hdc = BeginPaint(hWnd,&ps) ;
		T.fnt = hfnt ;
		oFnt = SelectObject(hdc, T.fnt) ;
		oPen = SelectObject(hdc, blackPen) ;
		T.bM  = OPAQUE ;
		T.bC  = Cr[YELLOW] ;
		T.tC  = Cr[BLACK] ;

       hmemDC = CreateCompatibleDC(hdc) ;
       GetObject(bmDIA, sizeof(BITMAP), &bm ) ;
	      OBm = SelectObject(hmemDC, bmDIA) ;

	if (gotimage && AllDone) // Show these only when measurement completed
	{
	   if( !DIA )
               SelectObject(hmemDC, bmDIA) ;
            else
               SelectObject(hmemDC, bmDIAO) ;

               BitBlt(hdc, rctl[Dia].left,
                           rctl[Dia].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !PRJ )
               SelectObject(hmemDC, bmPRJ) ;
            else
               SelectObject(hmemDC, bmPRJO) ;

               BitBlt(hdc, rctl[Prj].left,
                           rctl[Prj].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !LEF )
               SelectObject(hmemDC, bmLEF) ;
            else
               SelectObject(hmemDC, bmLEFO) ;

               BitBlt(hdc, rctl[Lef].left,
                           rctl[Lef].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !RYT )
               SelectObject(hmemDC, bmRYT) ;
            else
               SelectObject(hmemDC, bmRYTO) ;

               BitBlt(hdc, rctl[Ryt].left,
                           rctl[Ryt].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !NPR )								// Null Profile Control
	   {
		   if (!(RYT || LEF || DIA))         	// if no PC selected,
               SelectObject(hmemDC, bmNULD) ;	// show off and disabled	
		   else									// else
               SelectObject(hmemDC, bmNUL) ;	// show off and enabled 
	   }
            else								// a PC selected,
               SelectObject(hmemDC, bmNULO) ;	// show on

               BitBlt(hdc, rctl[Npr].left,
                           rctl[Npr].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;
	   }

	   if (gotimage) // Allow Details dialogue only if image present
	   {
	   if( !DTL )
               SelectObject(hmemDC, bmDTL) ;
            else
               SelectObject(hmemDC, bmDTLO) ;

               BitBlt(hdc, rctl[Dtl].left,
                           rctl[Dtl].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;
	   }

	   SelectObject(hmemDC,OBm) ;
	   DeleteDC(hmemDC) ;


	  if (gotimage)
	  {
		        B = pBudResults ;
				M = pMeasure ;
			 rwid = (double)rimwid ;

			 switch (Units)
			 {
			 case IMPERIAL:
				 mult = (double)ws / DIBitsPerIn ; // inches per image unit
				 break ;
			 case METRIC:
				 mult = (double)ws / DIBitsPerMm ; // millimetres per image unit
				 break ;
			 case IMAGEUNITS:
			 default:
				 mult = 1.0 ;
				 break ;
			 }

		if (showImage)
		{
		   hmemDC = CreateCompatibleDC(hdc) ;

		 switch (which)
		 {
		 case GRAY:
		   hBm = _ISRGBToHBITMAP(pGRY, dibwid, dibhyt, NULL, hdc) ;
		   break ;

		 case SIGNIF:
		   hBm = _ISRGBToHBITMAP(pSTA, dibwid, dibhyt, NULL, hdc) ;
		   break ;

		 case COLOUR:
		 default:
		   hBm = _ISRGBToHBITMAP(pRGB, dibwid, dibhyt, NULL, hdc) ;
		   break ;
		}
          
          OBm = SelectObject(hmemDC, hBm) ;

          SetStretchBltMode(hdc, STRETCH_DELETESCANS) ;

          //Display the Bitmap
          
          StretchBlt(hdc,rcresimg.left,
                         rcresimg.top,
                         rcresimg.right - rcresimg.left,
                         rcresimg.bottom - rcresimg.top,
                         hmemDC,
						 xsa,ysa,
					     ws,hs,
                         SRCCOPY) ;
                     
          SelectObject(hmemDC,OBm) ;
          DeleteObject(hBm) ;
          DeleteDC(hmemDC) ;
		}
	
	  if (autotracked && showTrack) // draw the tracks on the results image
	  {	 
		  int plot_it ;

		  SelectObject(hdc, ltbluePen) ;

		  for ( i = 0, plot_it = 0 ; i < hs ; i++ )
		  {
				  if ((s = Tk.Beplft[i]) >= 0)
				  {
					  Bf.x = s ;
					  Bf.y = hs - i ;

					  InsetToCli(&Sc, &Bf) ;

			      py1 = MulDiv(Sc.y - rcimg.top,  rimhyt, bimhyt) + rcresimg.top ;
			      px1 = MulDiv(Sc.x - rcimg.left, rimwid, bimwid) + rcresimg.left ;

				   if (!plot_it)
				   {
					   MoveToEx( hdc, px1 - 1, py1, NULL) ;
					   plot_it = 1 ;
				   }
				   else
					   LineTo( hdc, px1, py1) ;
				  }
		  }

		  for ( i = 0, plot_it = 0 ; i < hs ; i++ )
		  {
				  if ((s = Tk.Bepryt[i]) >= 0)
				  {
					  Bf.x = s ;
					  Bf.y = hs - i ;

					  InsetToCli(&Sc, &Bf) ;

			      py1 = MulDiv(Sc.y - rcimg.top,  rimhyt, bimhyt) + rcresimg.top ;
			      px1 = MulDiv(Sc.x - rcimg.left, rimwid, bimwid) + rcresimg.left ;

				   if (!plot_it)
				   {
					   MoveToEx( hdc, px1, py1, NULL) ;
					   plot_it = 1 ;
				   }
				   else
					   LineTo( hdc, px1 - 1, py1) ;
				  }
		  }
	  }

	  if (TOPSET && showGrid)	// draw the top pole cross
	  {
		px = (int)(pBudResults->BudTopPoleX * rwid) + rcresimg.left ;
		py = rcresimg.bottom - (int)(pBudResults->BudTopPoleY * rwid) ;
		DrawCross(hWnd, invert, px,	py, 8, whitePen) ;
	  }

	  if (TOPSET && showAnnot)	// print co-ordinates of the upper pole
	  {
		sprintf(buff," (%3.2f %s, %3.2f %s) ",
			            pBudResults->BudTopPoleX * mult, unit[Units],
						pBudResults->BudTopPoleY * mult, unit[Units]) ;
		GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		T.bC = Cr[RED] ;	// background colour
		T.tC = Cr[WHITE] ;	//       text colour
		T.x = px + 16 ;			// place to write
		T.y = py - sz.cy/2 ;
		PutText(hdc,&T,buff) ;  // write the text
		T.bC = Cr[YELLOW] ;		// revert
		T.tC = Cr[BLACK] ;
	  }

	  if (BOTSET && showGrid)	// draw the lower pole cross
	  {
		px = (int)(pBudResults->BudBotPoleX * rwid) + rcresimg.left ;
		py = rcresimg.bottom - (int)(pBudResults->BudBotPoleY * rwid) ;
		DrawCross(hWnd, invert, px, py, 8, whitePen) ;
	  }
	  
	  if (BOTSET && showAnnot)	// print co-ordinates of the lower pole
	  {
		sprintf(buff," (%3.2f %s, %3.2f %s) ",
			            pBudResults->BudBotPoleX * mult, unit[Units],
						pBudResults->BudBotPoleY * mult, unit[Units]) ;
		GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		T.bC = Cr[RED] ;
		T.tC = Cr[WHITE] ;
		T.x = px + 28 ;
		T.y = py - sz.cy/2 ;
		PutText(hdc,&T,buff) ;
		T.bC = Cr[YELLOW] ;
		T.tC = Cr[BLACK] ;
	  }


	  if (TOPSET && BOTSET)
	  {
			int xb, yb, xt, yt ;

		if (showGrid) // interpole line 
		{
		xb = (int)(pBudResults->BudBotPoleX * rwid) + rcresimg.left ;
		yb = rcresimg.bottom - (int)(pBudResults->BudBotPoleY * rwid) ;
		xt = (int)(pBudResults->BudTopPoleX * rwid) + rcresimg.left ;
		yt = rcresimg.bottom - (int)(pBudResults->BudTopPoleY * rwid) ;

	   	if (matchbend)
		// if snapping Path Curve to bud, connect poles
		// through mid-points of levels
		{
			if (EdgeDone[1] == BOTH)
			{
		        px2 = (int)(MidPt[1].x * rwid)+ rcresimg.left ;
		        py2 = rcresimg.bottom - (int)(MidPt[1].y * rwid) ;
    		    Draw( hWnd, xb, yb, px2, py2, whitePen ) ;
			}

			for ( i = 2 ; i <= Levels ; i++ )
			{
			  if ((EdgeDone[i] == BOTH) && (EdgeDone[i-1] == BOTH))
			  {
		        px1 = (int)(MidPt[i-1].x * rwid)+ rcresimg.left ;
		        py1 = rcresimg.bottom - (int)(MidPt[i-1].y * rwid) ;

		        px2 = (int)(MidPt[i].x * rwid)+ rcresimg.left ;
		        py2 = rcresimg.bottom - (int)(MidPt[i].y * rwid) ;

    			Draw( hWnd, px1, py1, px2, py2, whitePen ) ;
			  }
			}

			if (EdgeDone[Levels] == BOTH)
			{
		        px1 = (int)(MidPt[Levels].x * rwid)+ rcresimg.left ;
		        py1 = rcresimg.bottom - (int)(MidPt[Levels].y * rwid) ;
    		    Draw( hWnd, px1, py1, xt, yt, whitePen ) ;
			}

		}
		else  // just connect poles directly
			Draw( hWnd, xb, yb, xt, yt, whitePen ) ;
		}

		if (showAnnot)	// print interpole distance
		{
			sprintf(buff," IPD: %4.3f %s, Tilt: %3.1f deg. ",
			         pBudResults->BudLength * mult, unit[Units],
					 pBudResults->BudTilt * r2d - 90.0) ;

		GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		//T.x = xt - (sz.cx + 16) ;
		T.x = xb - sz.cx/2 ;	// put text below and centered on the bottom pole
		T.y = yb + 2*sz.cy ;
		T.tC = Cr[WHITE] ;
		T.bC = Cr[BLUE] ;
		PutText(hdc,&T,buff) ;
		T.tC = Cr[BLACK] ;
		T.bC = Cr[YELLOW] ;
		} 
	  }

	  for ( i = 1 ; i <= Levels ; i++)
	    {
			  HPEN nib, nib1, nib2 ;
			   int arm, mx, my ;

		  switch( EdgeDone[i])
		  {
		  case LEFT:
		if (showGrid)
		{
		   px = (int)(M->iLeftCut[i].x * rwid) + rcresimg.left ;
		   py = rcresimg.bottom - (int)(M->iLeftCut[i].y * rwid) ;
		   switch (LEdgeOrg[i])
		   {
		   case TRACKED:
			   nib = whitePen ;
			   arm = 5 ;
		       break ;
		   case EYEBALLED:
			   nib = redPen ;
			   arm = 7 ;
			   break ;
		   case PREDICTED:
			   nib = goldPen ;
			   arm = 7 ;
		   case NONE:
		   default: break ;
		   }
		   DrawCross(hWnd, invert, px, py, arm, nib) ;
		}

		if (showAnnot && !(RYT||LEF||DIA))
		{
		sprintf(buff," %4.3f ", M->iLeftRad[i] * mult) ;
		GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		T.x = px - (sz.cx + 10) ;
		T.y = py - sz.cy/2 ;
		PutText(hdc,&T,buff) ;
		} 
			  break ;

		  case RIGHT:
		if (showGrid)
		{
		   px = (int)(M->iRightCut[i].x * rwid) + rcresimg.left ;
		   py = rcresimg.bottom - (int)(M->iRightCut[i].y * rwid) ;

		   switch (REdgeOrg[i])
		   {
		   case TRACKED:
			   nib = whitePen ;
			   arm = 5 ;
		       break ;
		   case EYEBALLED:
			   nib = redPen ;
			   arm = 7 ;
			   break ;
		   case PREDICTED:
			   nib = goldPen ;
			   arm = 7 ;
		   case NONE:
		   default: break ;
		   }
		   DrawCross(hWnd, invert, px, py, arm, nib) ;
			   break ;
		}

		if (showAnnot && !(RYT||LEF||DIA))
		{
		sprintf(buff," %4.3f ", M->iRightRad[i] * mult) ;
		GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		T.x = px + 10 ;
		T.y = py - sz.cy/2 ;
		PutText(hdc,&T,buff) ;
		}
			  break ;

		  case BOTH:
			  if (showGrid)
			  {
		   switch (LEdgeOrg[i])
		   {
		   case TRACKED:
		   nib1 = whitePen ;
		       break ;
		   case EYEBALLED:
		   nib1 = redPen ;
			   break ;
		   case PREDICTED:
		   nib1 = goldPen ;
			   break ;
		   case NONE:
		   default:
		   nib1 = blackPen ; 
			   break ;
		   }

		   switch (REdgeOrg[i])
		   {
		   case TRACKED:
		   nib2 = whitePen ;
		       break ;
		   case EYEBALLED:
		   nib2 = redPen ;
			   break ;
		   case PREDICTED:
		   nib2 = goldPen ;
			   break ;
		   case NONE:
		   default:
		   nib2 = blackPen ; 
			   break ;
		   }
			    // midpoint crosshair

		    mx = (int)(MidPt[i].x * rwid) + rcresimg.left ;
		    my = rcresimg.bottom - (int)(MidPt[i].y * rwid) ;

			// invisible midpoint rects for mouse pointing

			SetRect(&rcmidpt[i], mx - 6, my - 6, mx + 6, my + 6) ; 

		   nib = IncludeLev[i] ? nib1 : blackPen ;

		DrawCross(hWnd, invert, mx, my, 3, nib) ;

		       // left crosshair
		
		   px1 = (int)(M->iLeftCut[i].x * rwid) + rcresimg.left ;
		   py1 = rcresimg.bottom - (int)(M->iLeftCut[i].y * rwid) ;

		DrawCross(hWnd, invert, px1, py1, 3, nib) ;

			   // line from midpoint to left edge
		          Draw(hWnd, px1, py1, mx, my, nib) ; 
			  }

		if (showAnnot && !(RYT||LEF||DIA))
		{	                 // left radius annotation
		sprintf(buff," %4.3f ", M->iLeftRad[i] * mult) ;
		GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		T.x = px1 - (sz.cx + 10) ;
		T.y = py1 - sz.cy/2 ;
		PutText(hdc,&T,buff) ;
		}

		if (showGrid)
		{
		   nib = IncludeLev[i] ? nib2 : blackPen ; 

			   // right crosshair
		   px2 = (int)(M->iRightCut[i].x * rwid) + rcresimg.left ;
		   py2 = rcresimg.bottom - (int)(M->iRightCut[i].y * rwid) ;
		DrawCross(hWnd, invert, px2, py2, 3, nib) ;

			   // line from midpoint to right edge
		          Draw(hWnd, mx, my, px2, py2, nib) ;
		}
				  
		if (showAnnot) 
		{               // right radius and diameter annotations
			if (!(RYT||LEF||DIA))
			{
 		      sprintf(buff," %4.3f ", M->iRightRad[i] * mult) ;
		      GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		      T.x = px2 + 10 ;
		      T.y = py2 - sz.cy/2 ;
		      PutText(hdc,&T,buff) ;
		      sprintf(buff," %4.3f ", M->iDiameter[i] * mult) ;
		      GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		      T.bC = Cr[GREEN] ;
		      T.tC = Cr[MAGENTA] ;
		      T.x = px2 + 16 + sz.cx ;
		      T.y = py2 - sz.cy/2 ;
		      PutText(hdc,&T,buff) ;
		      T.bC = Cr[YELLOW] ;
		      T.tC = Cr[BLACK] ;
			}
			else
		if (IncludeLev[i])
		{
		if (PRJ)
			{
				if (LEF) sprintf(buff," %3.2f%% ", pBudResults->LProjDev[i]) ;
 				if (RYT) sprintf(buff," %3.2f%% ", pBudResults->RProjDev[i]) ;
 				if (DIA) sprintf(buff," %3.2f%% ", pBudResults->BProjDev[i]) ;
			}
			else
			{
				if (LEF) sprintf(buff," %3.2f%% ", pBudResults->LRegrDev[i]) ;
 				if (RYT) sprintf(buff," %3.2f%% ", pBudResults->RRegrDev[i]) ;
 				if (DIA) sprintf(buff," %3.2f%% ", pBudResults->BRegrDev[i]) ;
			}
		    GetTextExtentPoint32(hdc,buff,strlen(buff),&sz) ;
		if (LEF)
		     T.x = px1 - (sz.cx + 20) ;
		else // is right, or diameters
		     T.x = px2 + 20 ;

			 T.y = py2 - sz.cy/2 ;
		     PutText(hdc,&T,buff) ;
		}
	    }
	          break ;

		  case NONE:
		  default:
			  break ;
	   } // end switch( EdgeDone[i] )
	 } // end for ( i = 1 ; i <= Levels ; i++ )

		  if (LEF)
		  {
			 if (PRJ)
			 {
			  PathCurve( hWnd,		 LEFT, PROJ, whitePen) ;
			  //PathCurve( hWndBud,    LEFT, PROJ, whitePen) ;
			 }
			 else
			 {
			  PathCurve( hWnd,		 LEFT, REGR, whitePen ) ;
			  //PathCurve( hWndBud,    LEFT, REGR, whitePen ) ;
			 }
		  }

		  if (RYT)
		  {
			 if (PRJ)
			 {
			  PathCurve( hWnd,		 RIGHT, PROJ, whitePen) ;
			  //PathCurve( hWndBud,    RIGHT, PROJ, whitePen) ;
			 }
			 else
			 {
			  PathCurve( hWnd,		 RIGHT, REGR, whitePen ) ;
			  //PathCurve( hWndBud,    RIGHT, REGR, whitePen ) ;
			 }
		  }

		  if (DIA)
		  {
			 if (PRJ)
			 {
			  PathCurve( hWnd,		 BOTH, PROJ, yellowPen) ;
			  //PathCurve( hWndBud,    BOTH, PROJ, yellowPen) ;
			 }
			 else
			 {
			  PathCurve( hWnd,		 BOTH, REGR, yellowPen ) ;
			  //PathCurve( hWndBud,    BOTH, REGR, yellowPen ) ;
			 }
		  }
	    }
{
	char blank[] = {'\0'} ;

	   if (DIA) titleptr = PRJ? ResultCombo[0] : ResultCombo[3] ;
	   else
	   if (LEF) titleptr = PRJ? ResultCombo[1] : ResultCombo[4] ;
	   else
	   if (RYT) titleptr = PRJ? ResultCombo[2] : ResultCombo[5] ;
	   else     
	   if (strlen(DropPath(szFile)) != 0) 
		  titleptr = DropExt(DropPath(szFile)) ;
	   else
		  titleptr = blank ;

	   strcpy(szResWindowTit, szResWindowTxt) ;
	   strcat(szResWindowTit, titleptr) ;
	   SetWindowText(hWnd,szResWindowTit) ;

	   GetTextExtentPoint32(hdc, titleptr, strlen(titleptr), &sz) ;
	   T.x = rcrslt.left + 4 ;
	   T.y = rcresimg.top - (sz.cy + 3) ;
	   T.tC = Cr[YELLOW] ;
	   T.bC = Cr[BLACK] ;
	   PutText(hdc, &T, titleptr) ;
}
		SelectObject(hdc, oFnt) ;
		SelectObject(hdc, oPen) ;
		EndPaint(hWnd,&ps) ;
		break ;

case WM_MOVE:
case WM_SIZE:
case WM_WINDOWPOSCHANGED:
        AdjustDisplays() ;
        ivrc(hWnd, NULL, TRUE) ;
        UpdateWindow(hWnd) ;
        return 0 ;
        break ;

case WM_CREATE:
	   hAccel2 = LoadAccelerators(hInst,MAKEINTRESOURCE(IDR_ACCELERATOR2)) ;
         bmPRJ = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_PROJECTIVE)) ;
        bmPRJO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_REGRESSION)) ;
         bmLEF = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_LEFT)) ;
        bmLEFO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_LEFT_ON)) ;
         bmRYT = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_RIGHT)) ;
        bmRYTO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_RIGHT_ON)) ;
		 bmDIA = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_DIAMETER)) ;
		bmDIAO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_ON_DIAMETER_ON)) ;
		 bmDTL = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GIVE_DETAILS)) ;
		bmDTLO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_GIVE_DETAILS_ON)) ;
		 bmNUL = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NULL_PROF)) ;
		bmNULO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NULL_PROF_ON)) ;
		bmNULD = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_NULL_PROF_DIS)) ;
		return 0L ;
	break ;

case WM_DESTROY:
        DeleteObject(bmPRJ) ;
        DeleteObject(bmPRJO) ;
        DeleteObject(bmLEF) ;
        DeleteObject(bmLEFO) ;
        DeleteObject(bmRYT) ;
        DeleteObject(bmRYTO) ;
        DeleteObject(bmDIA) ;
        DeleteObject(bmDIAO) ;
        DeleteObject(bmDTL) ;
        DeleteObject(bmDTLO) ;
        DeleteObject(bmNUL) ;
        DeleteObject(bmNULO) ;
        DeleteObject(bmNULD) ;
		KillTimer(hWnd,IDT_VOCTIMER) ;
		return 0L ;
	break;

        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
	}

	
	return ((long)NULL) ;
} // end of ResultsProc

void PutText(HDC hdc, LPTXT T, char * txt)
{
	UINT len ;

		 len = strlen(txt) ;
		       SetTextColor(hdc,T->tC) ;
		         SetBkColor(hdc,T->bC) ;
		          SetBkMode(hdc,T->bM) ;

		TextOut(hdc, T->x, T->y, txt, len ) ; 
}

/****************************************************************
			   Record Dimensions
 ****************************************************************/
int RecordDimensions( void )
	{
	  LPBUDRESULTS B ;
			  char * units[] = {"in","mm","iu"} ;
			   int i ;
		    double factor ;

		             B = pBudResults ;
		DimensionItems = 0 ;
	
		switch (Units)
		{
		case IMPERIAL:
			factor = (double)ws / DIBitsPerIn ;	// inches per image unit
			break ;
		case METRIC:
			factor = (double)ws / DIBitsPerMm ;	// millimetres per image unit
			break ;
		case IMAGEUNITS:
		default:
			factor = 1.0 ;
			break ;
		}

		sprintf(DimenCombo[DimensionItems++],
			    "IPD: %4.3f %s   TILT: %4.3f degrees",
			    pBudResults->BudLength * factor,
				units[Units],
				pBudResults->BudTilt * r2d - 90.0
				) ;

		sprintf(DimenCombo[DimensionItems++],
				"LoPole (%4.3f%s, %4.3f%s)    HiPole (%4.3f%s, %4.3f%s)",
				pBudResults->BudBotPoleX * factor, units[Units],
				pBudResults->BudBotPoleY * factor, units[Units],
				pBudResults->BudTopPoleX * factor, units[Units],
				pBudResults->BudTopPoleY * factor, units[Units]
				) ;

		sprintf(DimenCombo[DimensionItems++],
			"       Diam.       Left R.      Right R.") ;

	for (i = Levels ; i >= 1 ; i-- )
	{
	sprintf(DimenCombo[DimensionItems++],
	        "%d:  %6.4f %s   %6.4f %s   %6.4f %s",
			 i ,
			 pMeasure->iDiameter[i] * factor,
			 units[Units],
	         pMeasure->iLeftRad[i]  * factor,
			 units[Units],
			 pMeasure->iRightRad[i] * factor,
			 units[Units]) ;
	}
	 return (DimensionItems) ;
}

/****************************************************************
			   Record Lambdas & MRDS
 ****************************************************************/
int RecordLambdas( void )
{
	  LPBUDRESULTS B ;

		B = pBudResults ;
		ResultItems = 0 ;
		  toArchive = 1 ;

 		 sprintf(ResultCombo[ResultItems++],
			    "Lambda %4.3f MRD %3.2f%% Proj. on %d Diameters",
			     B->DiamProjLambda, B->DiamProjMRD, Levels) ;

		 sprintf(ResultCombo[ResultItems++],
			    "Lambda %4.3f MRD %3.2f%% Proj. on %d Left Radii",
			     B->LeftProjLambda, B->LeftProjMRD, Levels) ;

		 sprintf(ResultCombo[ResultItems++],
			    "Lambda %4.3f MRD %3.2f%% Proj. on %d Right Radii",
			     B->RightProjLambda, B->RightProjMRD, Levels) ;

		 sprintf(ResultCombo[ResultItems++],
			    "Lambda %4.3f MRD %3.2f%% Regr. on %d Diameters",
			     B->DiamRegrLambda, B->DiamRegrMRD, Levels) ;

		 sprintf(ResultCombo[ResultItems++],
			    "Lambda %4.3f MRD %3.2f%% Regr. on %d Left Radii",
			     B->LeftRegrLambda, B->LeftRegrMRD, Levels) ;

		 sprintf(ResultCombo[ResultItems++],
			    "Lambda %4.3f MRD %3.2f%% Regr. on %d Right Radii",
			     B->RightRegrLambda, B->RightRegrMRD, Levels) ;

		 return (ResultItems) ;

}

/***************************************************************************
          ScanWndProc:

          Show the line-scan graphs in own window.
		  (Modified 19/01/2001 to work entirely from the RGB buffer.) 

****************************************************************************/
long CALLBACK  ScanWndProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
  	     HWND hW ;
  PAINTSTRUCT ps ;
          HDC hdc, hmemDC ;
	   BITMAP bm ;
	  HBITMAP oBm ;
         HPEN oPen ;
	    POINT pt, mpt ;
 static POINT box, cpt, cupt, tpt ;
          int width, xp, yp, yoff, xoff ;
		  int xsc1, ysc1, xsc2, ysc2 ;
		  int hsc1 , hsc2 ;
	   double scaler1, scaler2, input1, input2, hMul ;
	   static i, xcur, nPos, nhPos ;
	   static HUE = btn_up, LUM = btn_down, CWH = btn_up ;

		 switch (message)
    {
        case WM_COMMAND:       /* message: command from application menu */

         switch( LOWORD(wParam) )
         {
		 case SCROLLS:
			 SetScrollPos(hScrSmooth,SB_CTL,scansmooth,    TRUE) ;
			 SetScrollPos(hScrTh,SB_CTL,THMAX - threshold, TRUE) ;
			 SetScrollPos(hScrGain,SB_CTL,diffgain,        TRUE) ;
			 break ;

		  case WM_MOUSEGONE:
		   if (CurrentTip != (HWND)NULL)
		   RemoveTip() ;
		   return 0L ;

          case IDM_SHOW_SCAN:
          if ( scanning && graphing )
		  {
			      ShowWindow(hWnd, SW_SHOW) ;
				SetWindowPos(hWnd, HWND_TOP,
					         0,0,0,0,
							 SWP_NOSIZE|SWP_NOMOVE) ;
			  ivrc(hWnd,NULL,TRUE) ;
		       ShowSmoothing(hWnd) ;
		  }
          else
          ShowWindow(hWnd, SW_HIDE) ;
          break ;
          
          case IDM_SCAN:
		  ivrc(hWnd, NULL, TRUE) ;
		   vrc(hWnd, &rcscb ) ;	 // rescue the button bar
		   vrc(hWnd, &rcscl ) ;  // and the vertical scales
          UpdateWindow(hWnd) ;
          break ;
         }
        break ;

		 case WM_TIMER:
			 switch( wParam)
			 {
			case IDT_TIPDWELL:
			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				 DestroyWindow(hWndInfo[UseCtl]) ;
				 CurrentTip = (HWND)NULL ;
				 hWndOfCurrentTip = (HWND)NULL ;
			 }
			 KillTimer(hWnd, IDT_TIPDWELL) ;
			 Dwelling[UseCtl] = 0 ;
				return 0L ;

			case IDT_TIPDEFER:

			 KillTimer(hWnd,IDT_TIPDEFER) ;
			 Deferred[UseCtl] = 0 ;

			 GetCursorPos(&cupt) ;
			 ScreenToClient(hWnd,&cupt) ;
			 if (PtInRect(&rctl[UseCtl],cupt))
			 {
				PutTip(hWnd, 0, 3) ;
			 }

			    break ;
			 }
			 return 0L ;
			 break ;

		case WM_NCHITTEST: // works for any mouse event in this window

	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;
		
		 case WM_MOUSEMOVE:

			pt.x = LOWORD(lParam) ;
			pt.y = HIWORD(lParam) ;

		 if (showtips || sounds)
		 {
			GetCursorPos(&cpt) ;
			ScreenToClient(hWnd,&cpt) ;
			GetTip( hWnd, Lum, Smd, cpt) ;
			if (sounds)
			GetVoc(hWnd, Lum, Smd, cpt) ;
		 }

		break;

		 case WM_HSCROLL:

			      hW = (HWND)lParam ;
			 	nhPos =  (int)HIWORD(wParam) ;

		switch (LOWORD(wParam))
		{
		 case SB_THUMBTRACK:
			 if (hW == hScrSmooth)
			 {
			 scansmooth = nhPos ;
			 SetScrollPos(hScrSmooth, SB_CTL, scansmooth, TRUE) ;
			 }
             ShowSmoothing(hWnd) ;
			 break ;
		 case SB_LINEUP:
			 if (hW == hScrSmooth)
			 {
			 scansmooth -= 1 ;
			 if (scansmooth <0) scansmooth = 0 ;
			 SetScrollPos(hScrSmooth, SB_CTL, scansmooth, TRUE) ;
			 }
             ShowSmoothing(hWnd) ;
			 break ;
		 case SB_LINEDOWN:
			 if (hW == hScrSmooth)
			 {
			 scansmooth += 1 ;
			 if (scansmooth > 30) scansmooth = 30 ;
			 SetScrollPos(hScrSmooth, SB_CTL, scansmooth, TRUE) ;
			 }
             ShowSmoothing(hWnd) ;
			 break ;
		 case SB_PAGEUP:
			 if (hW == hScrSmooth)
			 {
			 scansmooth -= 5 ;
			 if (scansmooth < 0) scansmooth = 0 ;
			 SetScrollPos(hScrSmooth, SB_CTL, scansmooth, TRUE) ;
			 }
             ShowSmoothing(hWnd) ;
		     break ;
		 case SB_PAGEDOWN:
			 if (hW == hScrSmooth)
			 {
			 scansmooth += 5 ;
			 if (scansmooth > 30) scansmooth = 30 ;
			 SetScrollPos(hScrSmooth, SB_CTL, scansmooth, TRUE) ;
			 }
             ShowSmoothing(hWnd) ;
			 break ;
		
		default: break ;
		}

			 break ;

		 case WM_VSCROLL:

			      hW = (HWND)lParam ;
			 	nPos =  (int)HIWORD(wParam) ;

		switch (LOWORD(wParam))
		{
		 case SB_THUMBTRACK:
			 if (hW == hScrGain)
			 {
			 diffgain = nPos ;
			 SetScrollPos(hScrGain, SB_CTL, diffgain, TRUE) ;
			 }

			 if (hW == hScrTh)
			 {
			 threshold = THMAX - nPos ;
			 SetScrollPos(hScrTh, SB_CTL, nPos, TRUE) ;
			 }
			 SendMessage(hWnd, WM_COMMAND, IDM_SCAN, 0L) ;
			 break ;

		 case SB_LINEUP:
			 if (hW == hScrGain)
			 {
			 diffgain -= 4 ;
			 if (diffgain < 32) diffgain = 16 ;
			 SetScrollPos(hScrGain, SB_CTL, diffgain, TRUE) ;
			 }

			 if (hW == hScrTh)
			 {
			 threshold += 1 ;
			 if (threshold > THMAX) threshold = THMAX ;
			 SetScrollPos(hScrTh, SB_CTL, THMAX - threshold, TRUE) ;
			 }
			 SendMessage(hWnd, WM_COMMAND, IDM_SCAN, 0L) ;
			 break ;

		 case SB_LINEDOWN:
			 if (hW == hScrGain)
			 {
			 diffgain += 4 ;
			 if (diffgain > 512) diffgain = 512 ;
			 SetScrollPos(hScrGain, SB_CTL, diffgain, TRUE) ;
			 }

			 if (hW == hScrTh)
			 {
			 threshold -= 1 ;
			 if (threshold < 0) threshold = 0 ;
			 SetScrollPos(hScrTh, SB_CTL, THMAX - threshold, TRUE) ;
			 }
			 SendMessage(hWnd, WM_COMMAND, IDM_SCAN, 0L) ;
			 break ;

		 case SB_PAGEUP:
			 if (hW == hScrGain)
			 {
			 diffgain -= 16 ;
			 if (diffgain < 32) diffgain = 16 ;
			 SetScrollPos(hScrGain, SB_CTL, diffgain, TRUE) ;
			 }

			 if (hW == hScrTh)
			 {
			 threshold += 5 ;
			 if (threshold > THMAX) threshold = THMAX ;
			 SetScrollPos(hScrTh, SB_CTL, THMAX - threshold, TRUE) ;
			 }
			 SendMessage(hWnd, WM_COMMAND, IDM_SCAN, 0L) ;
		 break ;

		 case SB_PAGEDOWN:
			 if (hW == hScrGain)
			 {
			 diffgain += 32 ;
			 if (diffgain > 512) diffgain = 512 ;
			 SetScrollPos(hScrGain, SB_CTL, diffgain, TRUE) ;
			 }

			 if (hW == hScrTh)
			 {
			 threshold -= 5 ;
			 if (threshold < 0) threshold = 0 ;
			 SetScrollPos(hScrTh, SB_CTL, THMAX - threshold, TRUE) ;
			 }
			 SendMessage(hWnd, WM_COMMAND, IDM_SCAN, 0L) ;
			 break ;

		 default: break ;
		}

			 break ;

        case WM_MOVE:
        case WM_SIZE:
        case WM_WINDOWPOSCHANGED:
        AdjustDisplays() ;
        ivrc(hWnd,NULL,TRUE) ;
        //UpdateWindow(hWnd) ;
        ShowSmoothing(hWnd) ;
        return 0 ;
        break ;
        
        case WM_LBUTTONDOWN:

			mpt.x = LOWORD(lParam) ;
			mpt.y = HIWORD(lParam) ;

			if (PtInRect(&rctl[Hue],mpt))
			{
             Clicked[Hue] = 1 ;
			 KillTip(hWnd, Hue) ;
			 HUE = huesat = 1 ; LUM = 0 ; CWH = colwh = 0 ;
			 ivrc(hWnd,&rctl[Hue],FALSE) ;
			 ivrc(hWnd,&rctl[Lum],FALSE) ;
			 ivrc(hWnd,&rctl[Cwh],FALSE) ;
			}

			if (PtInRect(&rctl[Lum],mpt))
			{
             Clicked[Lum] = 1 ;
			 KillTip(hWnd, Lum) ;
			 HUE = huesat = 0 ; LUM = 1 ; CWH = colwh = 0 ;
			 ivrc(hWnd,&rctl[Hue],FALSE) ;
			 ivrc(hWnd,&rctl[Lum],FALSE) ;
			 ivrc(hWnd,&rctl[Cwh],FALSE) ;
			}

			if (PtInRect(&rctl[Cwh],mpt))
			{
             //Clicked[Cwh] = 1 ;
			 //KillTip(hWnd, Cwh) ;
			 HUE = huesat = 1 ; LUM = 0 ; CWH = colwh = 1 ;
			 ivrc(hWnd,&rctl[Hue],FALSE) ;
			 ivrc(hWnd,&rctl[Lum],FALSE) ;
			 ivrc(hWnd,&rctl[Cwh],FALSE) ;
			}
		break ;

		case WM_LBUTTONUP:

			mpt.x = LOWORD(lParam) ;
			mpt.y = HIWORD(lParam) ;

		break ;

		case WM_PAINT:
        hdc = BeginPaint(hWnd,&ps) ;


		  hmemDC = CreateCompatibleDC(hdc) ;
		GetObject(bmLUM,sizeof (BITMAP),&bm) ;
		oBm = SelectObject(hmemDC,bmLUM) ;

		if( !LUM )							   // for Lum/dLum button
               SelectObject(hmemDC, bmLUM) ;
            else
               SelectObject(hmemDC, bmLUMO) ;

               BitBlt(hdc, rctl[Lum].left,	  // show button
                           rctl[Lum].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

	   if( !HUE )							   // for Hue/Sat button
               SelectObject(hmemDC, bmHUE) ;
            else
               SelectObject(hmemDC, bmHUEO) ;

               BitBlt(hdc, rctl[Hue].left,	  // show button
                           rctl[Hue].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

		if( !CWH )							   // for Colour Wheel button
               SelectObject(hmemDC, bmCWH) ;
            else
               SelectObject(hmemDC, bmCWHO) ;

               BitBlt(hdc, rctl[Cwh].left,	  // show button
                           rctl[Cwh].top,
                           bm.bmWidth,
                           bm.bmHeight,
                      hmemDC, 0, 0, SRCCOPY ) ;

  if (gotimage && scanning && stored)
  {
	  static HBRUSH Br, oBr ;
	  static Ay1, By1 ;
	  static Ay2, By2 ;

  if (huesat)
  {scaler1 = 3.0 ; scaler2 = 1.0 ;}
  else
  {scaler1 = 256.0 ; scaler2 = diffgain ;}
  
  width = ws ;

  // blue, lum or hue graph

  xoff  = Inset[Scan1Window].xo ;
  yoff	= Inset[Scan1Window].yo ;
  hMul  = (double)Inset[Scan1Window].h / scaler1 ;

if (!huesat)
{

 // Draw box-cursors indicating the seek span.
 // Then draw the graphs on top of the boxes.

   Br   = CreateSolidBrush(RGB(220, 220, 220)) ;
  oBr   = SelectObject(hdc, Br) ;
  oPen  = SelectObject(hdc, whitePen) ;

   xsc1 = Inset[Scan1Window].w ;
   ysc1 = Inset[Scan1Window].yo ;
   hsc1 = Inset[Scan1Window].h ;
   xsc2 = Inset[Scan2Window].w ;
   ysc2 = Inset[Scan2Window].yo ;
   hsc2 = Inset[Scan2Window].h ;


Rectangle(hdc,
		       MulDiv(xINS - seekspan, xsc1, width) + xoff,
         Ay1 = rcscan.bottom - (hsc1 + ysc1),
		       MulDiv(xINS + seekspan, xsc1, width) + xoff,
         By1 = rcscan.bottom - ysc1) ;

Rectangle(hdc,
		       MulDiv(xINS - seekspan, xsc2, width) + xoff,
         Ay2 = rcscan.bottom - (hsc2 + ysc2),
		       MulDiv(xINS + seekspan, xsc2, width) + xoff,
         By2 = rcscan.bottom - ysc2) ;

		  SelectObject(hdc, oBr) ;
		  DeleteObject(Br) ;
}

  if (huesat) // draw graticule indicating basic colours, or the colour wheel
  {
	  int xp1 ;
	  int xp2 ;
	  xp1 = xoff ;
      xp2 = xoff + Inset[Scan1Window].w ;
	  
	  if (!colwh)
	  {
	  oPen = SelectObject(hdc, blueWPen) ;
	  yp = rcscan.bottom - (int)(0.0 * hMul + (double)yoff) ;
	  MoveToEx(hdc, xp1, yp, NULL) ;
	    LineTo(hdc, xp2, yp) ;

	  oPen = SelectObject(hdc, purpleWPen) ;
	  yp = rcscan.bottom - (int)(0.5 * hMul + (double)yoff) ;
	  MoveToEx(hdc, xp1, yp, NULL) ;
	    LineTo(hdc, xp2, yp) ;

	  oPen = SelectObject(hdc, redWPen) ;
	  yp = rcscan.bottom - (int)(1.0 * hMul + (double)yoff) ;
	  MoveToEx(hdc, xp1, yp, NULL) ;
	    LineTo(hdc, xp2, yp) ;

	  oPen = SelectObject(hdc, yellowWPen) ;
	  yp = rcscan.bottom - (int)(1.5 * hMul + (double)yoff) ;
	  MoveToEx(hdc, xp1, yp, NULL) ;
	    LineTo(hdc, xp2, yp) ;

	  oPen = SelectObject(hdc, greenWPen) ;
	  yp = rcscan.bottom - (int)(2.0 * hMul + (double)yoff) ;
	  MoveToEx(hdc, xp1, yp, NULL) ;
	    LineTo(hdc, xp2, yp) ;

	  oPen = SelectObject(hdc, cyanWPen) ;
	  yp = rcscan.bottom - (int)(2.5 * hMul + (double)yoff) ;
	  MoveToEx(hdc, xp1, yp, NULL) ;
	    LineTo(hdc, xp2, yp) ;

	  oPen = SelectObject(hdc, blueWPen) ;
	  yp = rcscan.bottom - (int)(3.0 * hMul + (double)yoff) ;
	  MoveToEx(hdc, xp1, yp, NULL) ;
	    LineTo(hdc, xp2, yp) ;
	  }
  }

// black pen for luminosity or hue

  oPen  = SelectObject(hdc, blackPen) ;

   for ( i = 0 ; i < width  ; i++ )
   {

 input1 = (huesat)? (hue[i] + 1.0) : (double)lum[i] ;

 xp = MulDiv(i, Inset[Scan1Window].w, width) + xoff ;

 yp = rcscan.bottom - (int)(input1 * hMul + (double)yoff) ;
            
   if (!i)
   MoveToEx(hdc, xp, yp, NULL) ;
   else
   LineTo(hdc, xp, yp) ;
   }
   
   // red pen, for saturation or diff.lum. graph
  oPen  = SelectObject(hdc,redPen) ;

  xoff  = Inset[Scan2Window].xo ;
  yoff  = Inset[Scan2Window].yo ;
  hMul  = (double)Inset[Scan2Window].h / scaler2 ;

   for ( i = 0 ; i < width ; i++ )
   {
 input2 = (huesat) ? sat[i] : (double)dlum[i] ;

  xp = MulDiv(i, Inset[Scan2Window].w, width) + xoff ;
  yp = rcscan.bottom - (int)(input2 * hMul + (double)yoff) ;
       
   if (!i)
   MoveToEx(hdc, xp, yp, NULL) ;
   else
   LineTo(hdc, xp, yp) ;
   }

   // Threshold line
   if (!huesat)
   {
	   xp = xoff ;
       yp = rcscan.bottom - (int)(threshold * hMul + (double)yoff) ;
	   MoveToEx(hdc, xp, yp, NULL) ;

	   xp = Inset[Scan2Window].w + xoff ;
	   LineTo(hdc, xp, yp) ;
   }

 oPen = SelectObject( hdc, yellowPen ) ; // graph cursor lines, tracking the bud cursor
 
 SetROP2(hdc, R2_XORPEN) ;	 // see the graphs "through" the cursor lines
 
 // The line cursors

 xp = MulDiv(xINS, Inset[Scan1Window].w, width) + xoff ;
 
 MoveToEx(hdc, xp, Ay1, NULL) ;
   LineTo(hdc, xp, By1 + 1) ;

 MoveToEx(hdc, xp, Ay2, NULL) ;
   LineTo(hdc, xp, By2 + 1) ;

 // If cursor on a peak, show an arrow to it,
 // indicating a "hit".

		 if (ISONPEAK)
		 {
	     xp = MulDiv(PeakAt[onPeak], Inset[Scan2Window].w, width) + xoff ;
	     yp = rcscan.bottom - (int)(PeakVal[onPeak] * hMul + (double)yoff) ; 
		 SelectObject(hmemDC,bmHIT) ;
		 
		 BitBlt(hdc,
			    xp -  4,
				yp - 40,
				9,
				25,
				hmemDC,0,0,SRCCOPY) ;
		 }

 //Mark above-threshold peaks.

 for (i = 0 ; i < nPeaks ; i++)
 {
	 xp = MulDiv(PeakAt[i], Inset[Scan2Window].w, width) + xoff ;
	 yp = rcscan.bottom - (int)(PeakVal[i] * hMul + (double)yoff) ; 
	 DrawMark(hWnd, xp, yp, 4, whitePen) ;
 }
 
 SetROP2( hdc, R2_COPYPEN) ;
 
  SelectObject( hdc,    oPen ) ;
  SelectObject( hmemDC, oBm ) ;
  }      
	    DeleteDC(hmemDC) ;
        EndPaint(hWnd,&ps) ;
        return 0 ;
        break ;
        
case WM_CREATE:
	   GetClientRect(hWnd,&rcscan) ;
	   hScrGain = CreateWindow(
		                      "SCROLLBAR",
		                       "",
							   WS_CHILD|SBS_VERT|WS_VISIBLE,
							   2,
							   rcscan.bottom - 110,
							   12, 80,
							   hWnd,
							   (HMENU)SCR_GAIN,
							   hInst,
							   NULL
	                          ) ;

	   if (!hScrGain) return FALSE ;

	   SetScrollRange(hScrGain,SB_CTL,16,512,TRUE) ;
	     SetScrollPos(hScrGain,SB_CTL,diffgain,TRUE) ;
		                   
	    hScrTh = CreateWindow(
		                      "SCROLLBAR",
		                      "",
							   WS_CHILD|SBS_VERT|WS_VISIBLE,
							   15,
							   rcscan.bottom - 110,
							   12, 80,
							   hWnd,
							   (HMENU)SCR_THRESH,
							   hInst,
							   NULL
	                          ) ;

	   if (!hScrTh) return FALSE ;

	   SetScrollRange(hScrTh,SB_CTL,0,THMAX,TRUE) ;
	     SetScrollPos(hScrTh,SB_CTL,THMAX - threshold,TRUE) ;

	   hScrSmooth = CreateWindow(
		                      "SCROLLBAR",
		                      "",
							   WS_CHILD|SBS_HORZ|WS_VISIBLE,
							   220,
							     2,
							    70,
							    16,
							   hWnd,
							   (HMENU)SCR_SMOOTH,
							   hInst,
							   NULL
	                          ) ;

	   if (!hScrSmooth) return FALSE ;

	   SetScrollRange(hScrSmooth,SB_CTL,0,10,TRUE) ;
	     SetScrollPos(hScrSmooth,SB_CTL,scansmooth,TRUE) ;

	     bmHUE = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_HUESAT)) ;
		bmHUEO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_HUESAT_ON)) ; 
		 bmLUM = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_LUMDLUM)) ; 
		bmLUMO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_LUMDLUM_ON)) ;
	     bmHIT = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_HIT)) ;
		 bmCWH = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CWH)) ;
		bmCWHO = LoadBitmap(hInst,MAKEINTRESOURCE(IDB_CWHO)) ;
		 return 0L ;
	break ;

case WM_DESTROY:
	DeleteObject(bmLUM) ;
	DeleteObject(bmLUMO) ;
	DeleteObject(bmHUE) ;
	DeleteObject(bmHUEO) ;
	DeleteObject(bmHIT) ;
	DeleteObject(bmCWH) ;
	DeleteObject(bmCWHO) ;
	return 0L ;
	break ;

        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
    }

    return ((long)NULL);
}


// begin insert

  void DirPlots(HDC hdc, int wd, int ht)
  {
	;
  }

  void DirectionalPlots(HDC hdc, int wd, int ht)
  {
   static    int i, inside, nd, s, xp, yp, transit ;
   static double oldang[500], newang, ival ;
   static    int oxp[500], oyp[500] ;

     HPEN oPen ;

			// number of tick intervals in AstGP
			nd = epdensity * (int)(floor(AstGP * SiDY / sitd) + 1.0) ;
			// the corresponding plotting time interval
			ival = AstGP / (double)nd ; 

			if (wantDateClick) // do just the clicked date
			{
				ep = clickedEp ; // clickedEp comes when the chart is clicked
				goto usedirectly ;
			}

		// else do the whole thing

		        for ( i = 1, inside = 0 ; i <= nd + 1 ; i++ )
		       {
					ep = (double)(i - 1) * ival + AstEp1 ;

usedirectly:			update() ;

					xp = ep2xp(ep) ;

			if (xp >= xlmar && xp < (wd + xlmar))
			{
				++inside ;

				Systemic( pSy, UseCentre) ; // get the plotting data for this epoch
			    Systemic(pVSy, UseCentre) ; // get the   viewer data for this epoch


//***********************************************************
if (PlotMot) // Systemic Motion Direction
			   {
			   SelectObject(hdc, ltbluePen) ; s = 2 ;

		    // Remove transition lines from longitude plot.

			 if (inside == 1) oldang[s] = Sy.gLongs[MOT] ;
                            newang = Sy.gLongs[MOT] ;

            transit = TestTransit(2.0 * oldang[s], 2.0 * newang, UNRANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * newang / pi +
			          (double)ylmar) ;

		  oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotMot)

//***********************************************************
if (PlotNEqLo) // Direction of Equatorial Lunar Nodal
			   {
			    s = 3 ;

		    // Remove transition lines from longitude plot.

			 if (inside == 1) oldang[s] = Sy.gLongs[EQN] ;
                            newang = Sy.gLongs[EQN] ;
                           transit = TestTransit(oldang[s], newang, RANGED) ;
			
			if (newang >= 3.0 * pi / 2.0)
				SelectObject(hdc, redPen) ;
			else
				SelectObject(hdc, ltbluePen) ;

			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

		  oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotNEqLo)

//***********************************************************
if (PlotNEcLo) // Direction of Ecliptic Lunar Nodal
			   {
			   SelectObject(hdc, redPen) ; s = 4 ;

		    // Remove transition lines from longitude plot.

			 if (inside == 1) oldang[s] = Sy.gLongs[NOD] ;
                            newang = Sy.gLongs[NOD] ;
                           transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

		  oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotNEcLo)


//***********************************************************
if (PlotPeriLo) // Direction of Perigee
			   {
			   s = 6 ;

		    // Remove transition lines from longitude plot.

			 if (inside == 1) oldang[s] = Sy.gLongs[PER] ;
                            newang = Sy.gLongs[PER] ;
						   transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

				 if (newang >= pi)
				 SelectObject(hdc, dkbluePen) ;
				 else
				 SelectObject(hdc, ltbluePen) ;

		  oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotPeriLo)

//***********************************************************
if (PlotDirMean) // Heliocentric or Geocentric direction of Cartesian Mean Body
			   {
			   SelectObject(hdc, ltbluePen) ; s = 7 ;

		    // Remove transition lines from longitude plot.

			if (GeocMeanBod)	// do geocentric direction
			{
			 if (inside == 1) oldang[s] = Sy.gmean_lo ;
								 newang = Sy.gmean_lo ;
			}
			else				// do heliocentric direction
			{
			 if (inside == 1) oldang[s] = Sy.hmean_lo ;
								 newang = Sy.hmean_lo ;
			}
                           transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotDirMean)

//***********************************************************
if (PlotSysDirMean) // Systemic Direction on Cartesian Mean Body
			   {
			   s = 8 ;

		    // Remove transition lines from longitude plot.

			 if (inside == 1) oldang[s] = Sy.bSysDir[MBD] ;
                            newang = Sy.bSysDir[MBD] ;
                           transit = TestTransit(2.0 * oldang[s], 2.0 * newang, UNRANGED) ;

			 if (newang > pi)
				 SelectObject(hdc, blkdotPen) ;
			 else
				 SelectObject(hdc, blackPen) ; 
			
			     yp = rcArc.bottom -
			          (int)((double)ht * newang / pi +
			          (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotSysDirMean)



// ON MEAN BODY

//***********************************************************
if (PlotVectorSum) // MAGNITUDE of the resultant of radii on Cartesian mean body
			{
			      s = 9 ;
			   oPen = SelectObject(hdc, ltredPen) ;
			     yp = rcArc.bottom - (int)((double)ht * (Sy.mVectSum / 10.0) + (double)ylmar) ;
				 
   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
				SelectObject(hdc, oPen) ;
			} // if (PlotVectorSum)


//***********************************************************
if (PlotVectorDir) // DIRECTION of the resultant of Radii on Cartesian Mean Body
			   {
			   SelectObject(hdc, ltredPen) ; s = 10 ;

		    // Remove transition lines from plot.

			 if (inside == 1) oldang[s] = Sy.mVectDir ;
                            newang = Sy.mVectDir ;
                           transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotVectorDir)

//***********************************************************
if (PlotVectorLat) // LATITUDE of resultant of Radii on Cartesian Mean Body
			   {
			   SelectObject(hdc, ltredPen) ; s = 11 ;

		    // Remove transition lines from plot.

			 if (inside == 1) oldang[s] = Sy.mVectLat + halfpi ;
                                 newang = Sy.mVectLat + halfpi ;
                           //transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotVectorLat)

//***********************************************************
if (PlotAccelDir) // Argument of Resultant Acceleration of Cartesian Mean Body
			   {
				s = 12 ;
				SelectObject(hdc, redPen) ; 

			 if (inside == 1) oldang[s] = Sy.maVectDir ;
                            newang = Sy.maVectDir ;
                           transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotAccelDir)

//***********************************************************
if (PlotAccelLat) // LATITUDE of Acceleration Vector of Cartesian Mean Body
			   {
				s = 13 ;
				SelectObject(hdc, redPen) ; 

			 if (inside == 1) oldang[s] = Sy.maVectLat + halfpi ;
                                 newang = Sy.maVectLat + halfpi ;
                           //transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotAccelDir)
//***********************************************************
if (PlotAccelSum)
				{
			   s = 14 ;
			   SelectObject(hdc, dkredPen) ;
			     yp = rcArc.bottom -
			          (int)((double)ht * (Sy.maVectSum / 100.0) + (double)ylmar) ; 
   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
				} // if (PlotAccelSum)





//VELOCITY OF MASS CENTRE
//***********************************************************
if (PlotCoMVectorSum) // MAGNITUDE of velocity vector of Mass Centre
		{
			      s = 15 ;
			   oPen = SelectObject(hdc, ltredPen) ;
			     yp = rcArc.bottom - (int)((double)ht * Sy.mMVectSum / 10.0 + (double)ylmar) ;
				 
   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
				SelectObject(hdc, oPen) ;
		} // if (PlotCoMVectorSum)

//***********************************************************
if (PlotCoMVectorDir) // DIRECTION of velocity vector of Mass Centre
			   {
			   SelectObject(hdc, dkredPen) ; s = 16 ;

		    // Remove transition lines from plot.
			 if (inside == 1) oldang[s] = Sy.mMVectDir ;
								 newang = Sy.mMVectDir ;
								transit = TestTransit(oldang[s], newang, RANGED) ;

			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi + (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotCoMVectorDir)

//***********************************************************
if (PlotCoMVectorLat) // LATITUDE of velocity vector of Mass Centre
			   {
				s = 17 ;
			    SelectObject(hdc, dkredPen) ;

		    // Remove transition lines from plot.
			 if (inside == 1) oldang[s] = latiply * Sy.mMVectLat + halfpi ;
								 newang = latiply * Sy.mMVectLat + halfpi ;
								//transit = TestTransit(oldang[s], newang, RANGED) ;

			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi + (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotCoMVectorLat)



//ACCELERATION OF MASS CENTRE
//***********************************************************
if (PlotCoMAccelDir) // DIRECTION of acceleration vector of Mass Centre
			   {
				s = 18 ;
				SelectObject(hdc, redPen) ; 

			 if (inside == 1) oldang[s] = Sy.mMaVectDir ;
								 newang = Sy.mMaVectDir ;
								transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi + (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotCoMAccelDir)

//***********************************************************
if (PlotCoMAccelLat) // LATITUDE of acceleration vector of Mass Centre
			   {
				s = 19 ;
				SelectObject(hdc, redPen) ; 

			 if (inside == 1) oldang[s] = latiply * Sy.mMaVectLat + halfpi ;
								 newang = latiply * Sy.mMaVectLat + halfpi ;
								//transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi + (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotCoMAccelLat)

//***********************************************************
if (PlotCoMAccelSum) // MAGNITUDE of acceleration vector of Mass Centre
				{
			   s = 20 ;
			   SelectObject(hdc, dkredPen) ;
			     yp = rcArc.bottom -
			          (int)((double)ht * (Sy.mMaVectSum / 10.0) + (double)ylmar) ;
				 
   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
				} // if (PlotCoMAccelSum)

//***********************************************************
//
// Tests of Predictive Models
// 
//***********************************************************
if (PlotTest)		// concerning velocity vector of mass centre, re helioc dir of MB
			{
				static double u, a, th ;
				 s = 21 ;
			   SelectObject(hdc, blackPen) ;
			    a = adiff(Sy.mMVectDir + pi/2.0, Sy.hmean_lo) ;

			   th = range90(a/2.0 + ashift/r2d) ; // wrt the mean body's helio direction

				u = pow(cos(th), 2.0) ;

			     yp = rcArc.bottom - (int)((double)ht * u + (double)ylmar) ;
				 
   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
		} // PlotTest

//***********************************************************
if (PlotTest1)		// concerning acceleration vector of mass centre, re helioc dir of MB
			{
				static double u, a, th ;
				 s = 22 ;
			   SelectObject(hdc, purplePen) ;
			    a = adiff(Sy.mMaVectDir, Sy.hmean_lo) ;

				th = range90(a/2.0 + ashift/r2d) ; // wrt the mean body's helio direction

				u = pow(cos(th), 2.0) ;

			     yp = rcArc.bottom -
			          (int)((double)ht * u + (double)ylmar) ;
				 
   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
		} // PlotTest1


//***********************************************************
if (PlotTest2)		// concerning acceleration re Jupiter, and the helioc dir of the MB
			{
				static double u, a, th ;
				 s = 23 ;
			   SelectObject(hdc, bluePen) ;
			     a = adiff(Sy.hLongs[JUP], Sy.hmean_lo) ;

			    th = range90(a/2.0 + ashift/r2d) ; // wrt the mean body's helio direction

			     u = pow(cos(th), 2.0) ;

			     yp = rcArc.bottom -
			          (int)((double)ht * u + (double)ylmar) ;
				 
   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
		} // PlotTest2

//**************************************************************
if (PlotSysDirOnSun) // Heliocentric Systemic Direction
			   {
			   SelectObject(hdc, redWPen) ; s = 27 ;

		    // Remove transition lines from longitude plot.

			 if (inside == 1) oldang[s] = Sy.bSysDir[SUN] ;
								 newang = Sy.bSysDir[SUN] ;
								transit = TestTransit(2.0 * oldang[s], 2.0 * newang, UNRANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * newang / pi +
			          (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlotSysDirOnSun)

//***********************************************************
if (PlothMassDir) // Heliocentric Direction of Mass Centre
			   {
			   SelectObject(hdc, purplePen) ; s = 28 ;

		    // Remove transition lines from plot.

			 if (inside == 1) oldang[s] = Sy.hMmean_lo ;
								 newang = Sy.hMmean_lo ;
								transit = TestTransit(oldang[s], newang, RANGED) ;
			
			     yp = rcArc.bottom -
			          (int)((double)ht * range(newang) / pi +
			          (double)ylmar) ;

			oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   } // if (PlothMassDir)

//***********************************************************
if (PlotSysAV)
{
			   oPen = SelectObject(hdc, bluePen) ; s = 35 ;

		    // Remove transition lines from plot.
			// data is already ranged

			 if (inside == 1) oldang[s] = 10.0 * Sy.sysav ;
								 newang = 10.0 * Sy.sysav ;
								transit = TestTransit(oldang[s], newang, UNRANGED) ;
			
			     yp = rcArc.bottom - (int)((double)ht * newang / pi + (double)ylmar) ;

		  oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			   SelectObject(hdc, oPen) ;

			   oPen = SelectObject(hdc, redPen) ;

			   s = 36 ;

			yp = rcArc.bottom - (int)((double)ht * (10.0 * Sy.frq[MER]) + (double)ylmar) ;

   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
			   SelectObject(hdc, oPen) ;

} // end if (PlotSysAV)

//***********************************************************
if (PlotMBhRadius)
{
			   s = 37 ;
			   oPen = SelectObject(hdc, redPen) ;
			     yp = rcArc.bottom -
			          (int)((double)ht * (Sy.hmean_ra / 20.0) + (double)ylmar) ;
   if (!wantDateClick)
			{

			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
				SelectObject(hdc, oPen) ;
}

//***********************************************************
if (PlotMBDirreSun) // plot Directions on MB relative to Sun dir on MB
		{
			int P ;
			HPEN Pen, oP ;
			double h ;

		  for (
			                P =  EAR ;
		                    P <= SUN ;
							P++
			  ) 
		  {
			  if (P == PLU || !DirBody[P]) continue ;

			  //shades of blue
			  Pen = CreatePen(PS_SOLID, 1, RGB(8 * P, 8 * P, 145 + 10 * P)) ;

			   oP = SelectObject(hdc, Pen) ; s = P - EAR + 38 ;

			   if (P == MOO)
			h = fabs(sin(adiff2(Sy.gLongs[P], Sy.hmean_lo))) ;
			   else
			h = fabs(sin(adiff2(Sy.hLongs[P], Sy.hmean_lo))) ;

				yp = rcArc.bottom -
			          (int)((double)ht * (h + 2.0) / 4.0 + (double)ylmar) ;

			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}

			SelectObject(hdc, oP) ;
			DeleteObject(Pen) ;
		}
		}

//***********************************************************
if (PlotSelLong) // plot selected longitude(s)
		{
		  static  int P ;
		  static HPEN Pen, oP ;
		  static first, last ;

		  if (do_helioc_dirs)
		  {first = EAR ; last = NEP ;}
		  if (do_geoc_dirs)
		  {first = MOO ; last = SUN ;}
		  if (do_meanbody_dirs)
		  {first = EAR ; last = SUN ;}

		  for (
			                P = first ;
		                    P <= last ;
							P++
			  ) 
		  {
			  if (P == PLU || !DirBody[P]) continue ;

			  //shades of red
			  Pen = CreatePen(PS_SOLID, 1, RGB(145 + 10 * P, 8 * P,  8 * P)) ;
			   oP = SelectObject(hdc, Pen) ; s = P - EAR + 91 ;
		    // Remove transition lines from direction plot
			// where possible.
			 if (inside == 1)
				 oldang[s] = (do_helioc_dirs)? Sy.hLongs[P] : (do_geoc_dirs)? Sy.gLongs[P] : Sy.hmeanbod_lo[P] ;

                    newang = (do_helioc_dirs)? Sy.hLongs[P] : (do_geoc_dirs)? Sy.gLongs[P] : Sy.hmeanbod_lo[P] ;

                   transit = TestTransit(oldang[s], newang, RANGED) ;

			     yp = rcArc.bottom - (int)((double)ht * range(newang) / pi + (double)ylmar) ;

		  oldang[s] = newang ;
   if (!wantDateClick)
		  plot(hdc, xp, yp, oxp, oyp, i, s, transit) ;

			 SelectObject(hdc, oP) ;
			 DeleteObject(Pen) ;
			} // end for ( P = EAR ;...
		} // end PlotSelLong



//***********************************************************
if (PlotAccBodies)	// Accelerations per included body
			{
		  static  int P ;
		  static HPEN Pen, oP ;
		  for (
			                P = EAR ; 
		                    P <= SUN ;
							P++
			  ) 
		  {
			  if (P == PLU ||  !AccBody[P]) continue ;

			// shades of green
			  Pen = CreatePen(PS_SOLID, 1, RGB(8 * P, 145 + 10 * P, 8 * P)) ; 
			   oP = SelectObject(hdc, Pen) ; s = P - EAR + 403 ;

			     yp = rcArc.bottom -
			          (int)((double)ht * (Sy.BodAcc[P] / 500.0) + (double)ylmar) ; 

				 
   if (!wantDateClick)
			{
			if (inside == 1)
				MoveToEx(hdc, oxp[s] = xp, oyp[s] = yp, NULL) ;
			else
			{
				MoveToEx(hdc, oxp[s], oyp[s], NULL) ;
				  LineTo(hdc, oxp[s] = xp, oyp[s] = yp) ;
			}
			}
				SelectObject(hdc, oP) ;
				DeleteObject(Pen) ;
		}
	} // PlotAccBodies


//***********************************************************
if (OpsViewEnable) // this has become the "Viewer Operations Enabler"
{

		// Run the viewer - if it's enabled

	// This is inside the "plot directions" loop, and "fires" on each pass.
	// Moved here to the end of the loop, since it should not fire until
	// all its data has been made available.

	// This is not necessarily the best way to manage this!

			ivrc(hWndView, NULL, FALSE) ;
		    UpdateWindow(hWndView) ;

 
} // if (OpsViewEnable)

		} // end if (xp >= xlmar....
		if (wantDateClick || wantMousedEp) break ; // break out of for (i..) loop
       } // end for ( i = 1 ;..  drop out of loop..
		inside = 0 ;

} //end  DirectionalPlots()
// End insert


//***********************************************************
//	All this, just to display one bloody number!
//***********************************************************
void ShowSmoothing( HWND hWnd )
{
  static char sm_level[4] = "\0" ;
    HFONT oFnt ;
	  HDC hdc ;

	  sprintf(sm_level," Smoothing Level: %2.2d ", scansmooth ) ;

		   hdc = GetDC(hWnd) ;
          oFnt = SelectObject( hdc, hfnt ) ;  // get the font into it
		  SetBkColor(hdc, RGB(255, 255, 0)) ; // yellow background
          SetTextColor(hdc, RGB(0, 0, 0)) ;   // black text
          TextOut(hdc, 300,                   // print the coordinates
                       3,
                       sm_level,
                       strlen(sm_level)) ;
          SelectObject( hdc, oFnt ) ;		  // clean up
		  ReleaseDC(hWnd,hdc) ;

}

//******************************************************************
//	Astronomy (Lunar Alignments)
//	Alignment count indices now match: that is, the first found
//  has an index of 1.
//*******************************************************************/

BOOL CALLBACK AlignDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
#define D1 0
#define D2 1
#define M1 2
#define M2 3
#define Y1 4
#define Y2 5
#define PL 6
#define CE 7

	       BOOL snafu ;
	static BOOL BO ;
	static BOOL F = FALSE, T = TRUE ;
	static HWND EDDy1, EDMo1, EDYr1, hW ;
	static HWND EDDy2, EDMo2, EDYr2 ;
	static HWND UDDy1, UDMo1, UDYr1 ;
	static HWND UDDy2, UDMo2, UDYr2 ;
	static HWND EDRes, UDRes ;
	static  int CENTRE, PLANET, missing ;
	static  int E[8], SetUp = 0 ;
	static  int i ;
	static double ep1, ep2 ;
	static int alignments = -1 ;
	       char buff[20] ;
		   char result[180] ;
    static char szInit[] = "Missing Entries:-\n" ;
	static char szNote[255] ;
	static char * Gone[] = {"First Day\n",
		                    "Final Day\n",
							"First Month\n",
							"Final Month\n",
							"First Year\n",
							"Final Year\n",
							"Planet Selection\n",
							"Centre\n"} ;

	switch(msg)
	{

case WM_INITDIALOG:

		// Do this bit just once per session.
		if (!SetUp)
		{
		for (i = 0 ; i < 8 ; E[i++] = 0) ;
		SetUp = 1 ;
		}

		EDDy1 = GetDlgItem(hDlg,IDC_DAY_ONE      ) ;
		EDMo1 = GetDlgItem(hDlg,IDC_MON_ONE      ) ;
		EDYr1 = GetDlgItem(hDlg,IDC_YR_ONE       ) ;
		UDDy1 = GetDlgItem(hDlg,IDC_SPIN_DAY_ONE ) ;
		UDMo1 = GetDlgItem(hDlg,IDC_SPIN_MON_ONE ) ;
		UDYr1 = GetDlgItem(hDlg,IDC_SPIN_YR_ONE  ) ;
		EDDy2 = GetDlgItem(hDlg,IDC_DAY_TWO      ) ;
		EDMo2 = GetDlgItem(hDlg,IDC_MON_TWO      ) ;
		EDYr2 = GetDlgItem(hDlg,IDC_YR_TWO       ) ;
		UDDy2 = GetDlgItem(hDlg,IDC_SPIN_DAY_TWO ) ;
		UDMo2 = GetDlgItem(hDlg,IDC_SPIN_MON_TWO ) ;
		UDYr2 = GetDlgItem(hDlg,IDC_SPIN_YR_TWO  ) ;
		EDRes = GetDlgItem(hDlg,IDC_RESOLUTION   ) ;
		UDRes = GetDlgItem(hDlg,IDC_SPIN_RESOLUTION ) ;

			   SetUDRng(UDDy1, 31, 1) ;
			   SetUDPos(UDDy1, day1) ;
			   SetUDRng(UDMo1, 12, 1) ;
			   SetUDPos(UDMo1, mon1) ;
			   SetUDRng(UDYr1, 99, 0) ;
			   SetUDPos(UDYr1, year1) ;						
			   SetUDRng(UDDy2, 31, 1) ;
			   SetUDPos(UDDy2, day2) ;
			   SetUDRng(UDMo2, 12, 1) ;
			   SetUDPos(UDMo2, mon2) ;
			   SetUDRng(UDYr2, 99, 0) ;
	           SetUDPos(UDYr2, year2) ;
			   SetUDRng(UDRes, 100, 1) ;
			   if (align->interval == 0.0)
				   align->interval  = 0.01 ;
			   SetUDPos(UDRes,(int)(align->interval * 100.0)) ;

	sprintf(buff,"%3.2f", align->interval) ;
	SetDlgItemText(hDlg,IDC_RESOLUTION, buff) ;

	switch( UseCentre )
	{
	case EQ: CENTRE = IDC_EQUATORIAL ;    E[CE] = 1 ;
		break ;
	case GE:
	default: CENTRE = IDC_GEOCENTRIC ;    E[CE] = 1 ;
		break ;
	}

	CheckRadioButton(hDlg,IDC_GEOCENTRIC,
		                  IDC_EQUATORIAL,
						  CENTRE ) ;

	switch ( UsePlanet )
	{
	case SUN: PLANET = IDC_PICK_SUN ; E[PL] = 1 ;
		break ;
	case MER: PLANET = IDC_PICK_MER ; E[PL] = 1 ;
		break ;
	case VEN: PLANET = IDC_PICK_VEN ; E[PL] = 1 ;
		break ;
	case MAR: PLANET = IDC_PICK_MAR ; E[PL] = 1 ;
		break ;
	case JUP: PLANET = IDC_PICK_JUP ; E[PL] = 1 ;
		break ;
	case SAT: PLANET = IDC_PICK_SAT ; E[PL] = 1 ;
		break ;
	case URA: PLANET = IDC_PICK_URA ; E[PL] = 1 ;
		break ;
	case NEP: PLANET = IDC_PICK_NEP ; E[PL] = 1 ;
		break ;
	default:  PLANET = IDC_PICK_SAT ; E[PL] = 1 ;
		break ;
	}

 	CheckRadioButton(hDlg,IDC_PICK_SUN,
		                  IDC_PICK_NEP,
						  PLANET) ;

    return TRUE ;
	break ;

	   case WM_VSCROLL:

	    hW = (HWND)lParam ;

		    if (hW == UDRes) 
			{
			// NOT a buddy integer u/d ctl, so go get the position
		    // and multiply it by the factor
                align->interval = 0.01 * (double)GetUDPos(UDRes) ;
					
			// write the value to the edit ctl
                sprintf(buff,"%3.2f",align->interval) ;
				SetDlgItemText(hDlg,IDC_RESOLUTION,buff) ;
			}

			if (hW == UDDy1) 
			{	// ctl is set buddy integer, so sets edit box.
				// get the integer from the edit box
				day1 = GetDlgItemInt(hDlg,IDC_DAY_ONE, &snafu, FALSE) ;
        		Aflag(hDlg) ;
				E[D1] = 1 ;
			}

			if (hW == UDMo1)
			{
				mon1 = GetDlgItemInt(hDlg,IDC_MON_ONE, &snafu, FALSE) ;
        		Aflag(hDlg) ;
				E[M1] = 1 ;
			}

			if (hW == UDYr1)
			{
				year1 = GetDlgItemInt(hDlg,IDC_YR_ONE, &snafu, FALSE) ;
        		Aflag(hDlg) ;
				E[Y1] = 1 ;
			}

			if (hW == UDDy2)
			{
				day2 = GetDlgItemInt(hDlg,IDC_DAY_TWO, &snafu, FALSE) ;
        		Aflag(hDlg) ;
				E[D2] = 1 ;
			}

			if (hW == UDMo2)
			{
				mon2 = GetDlgItemInt(hDlg,IDC_MON_TWO, &snafu, FALSE) ;
        		Aflag(hDlg) ;
				E[M2] = 1 ;
			}

			if (hW == UDYr2)
			{
				year2 = GetDlgItemInt(hDlg,IDC_YR_TWO, &snafu, FALSE) ;
        		Aflag(hDlg) ;
				E[Y2] = 1 ;
			}

		   break ; // WM_VSCROLL


case WM_COMMAND:
	
	switch(LOWORD(wParam))
	{

	case IDC_RESOLUTION:
		GetDlgItemText(hDlg,IDC_RESOLUTION,buff,20) ;
		align->interval = atof(buff) ;

		SetUDPos(UDRes, (int)(align->interval * 100.0)) ;

		Aflag(hDlg) ;
		break ;

	case IDC_GEOCENTRIC:
		UseCentre = GE ;
		Aflag(hDlg) ;
		E[CE] = 1 ;
		break ;
	case IDC_EQUATORIAL:
		UseCentre = EQ ;
		Aflag(hDlg) ;
		E[CE] = 1 ;
		break ;

	case IDC_PICK_SUN:
		UsePlanet = SUN ;
		Aflag(hDlg) ;
		E[PL] = 1 ;
		break ;
	case IDC_PICK_MER:
		UsePlanet = MER ;
		Aflag(hDlg) ;
		E[PL] = 1 ;
		break ;
	case IDC_PICK_VEN:
		UsePlanet = VEN ;
		Aflag(hDlg) ;
		E[PL] = 1 ;
		break ;
	case IDC_PICK_MAR:
		UsePlanet = MAR ;
		Aflag(hDlg) ;
		E[PL] = 1 ;
		break ;
	case IDC_PICK_JUP:
		UsePlanet = JUP ;
		Aflag(hDlg) ;
		E[PL] = 1 ;
		break ;
	case IDC_PICK_SAT:
		UsePlanet = SAT ;
		Aflag(hDlg) ;
		E[PL] = 1 ;
		break ;
 	case IDC_PICK_URA:
		UsePlanet = URA ;
		Aflag(hDlg) ;
		E[PL] = 1 ;
		break ;
 	case IDC_PICK_NEP:
		UsePlanet = NEP ;
		Aflag(hDlg) ;
		E[PL] = 1 ;
		break ;

	case IDC_DAY_ONE:
		Aflag(hDlg) ;
		day1 = GetDlgItemInt(hDlg, IDC_DAY_ONE, &snafu, FALSE) ;
		E[D1] = 1 ;
		break ;

	case IDC_MON_ONE:
		Aflag(hDlg) ;
		mon1 = GetDlgItemInt(hDlg, IDC_MON_ONE, &snafu, FALSE) ;
		E[M1] = 1 ;
		break ;

	case IDC_YR_ONE:
		Aflag(hDlg) ;
		year1 = GetDlgItemInt(hDlg, IDC_YR_ONE, &snafu, FALSE) ;
		E[Y1] = 1 ;
		break ;

	case IDC_DAY_TWO:
		Aflag(hDlg) ;
		day2 = GetDlgItemInt(hDlg, IDC_DAY_TWO, &snafu, F) ;
		E[D2] = 1 ;
		break ;

	case IDC_MON_TWO:
		Aflag(hDlg) ;
		mon2 = GetDlgItemInt(hDlg, IDC_MON_TWO, &snafu, F) ;
		E[M2] = 1 ;
		break ;

	case IDC_YR_TWO:
		Aflag(hDlg) ;
		year2 = GetDlgItemInt(hDlg, IDC_YR_TWO, &snafu, F) ;
		E[Y2] = 1 ;
		break ;

	case IDC_UPDATE:

		strcpy(szNote, szInit) ;
		// Trap and tell about missing imprests.
		for ( i = 0, missing = 0 ; i < 7 ; i++ )
		if (!E[i])
		{
			missing = 1 ;
			strcat(szNote, Gone[i]) ;
		}

		if (missing)
			{
				msgbox = 1 ;
				MessageBox(hDlg,
						   szNote,
					      "Not Ready",
						   MB_OK) ;
				msgbox = 0 ;
				break ;
			}

 // Do the second date first
		 day = GetDlgItemInt(hDlg,IDC_DAY_TWO,&snafu,FALSE) ;
		  mo = GetDlgItemInt(hDlg,IDC_MON_TWO,&snafu,FALSE) ;
		  yr = GetDlgItemInt(hDlg,IDC_YR_TWO, &snafu,FALSE) ;
		  setepoch() ;

		  ep2 = ep ;

// Do the first date last
		 day = GetDlgItemInt(hDlg,IDC_DAY_ONE,&snafu,FALSE) ;
		  mo = GetDlgItemInt(hDlg,IDC_MON_ONE,&snafu,FALSE) ;
		  yr = GetDlgItemInt(hDlg,IDC_YR_ONE, &snafu,FALSE) ;
		  setepoch() ;

		  ep1 = ep ;

		  update() ;  // as it is starting epoch for search

		  if (ep2 <= ep1)
		  {
			  msgbox = 1 ;
			  MessageBox(hDlg,
			  "Start Epoch is later than\nor the same as the End Epoch",
			  "Bad Search Epochs",
			   MB_OK) ;
			  msgbox = 0 ; 
			  break ;
		  }

		  align->period   = ep2 - ep1 ;	 // grand period of search
		  align->centre   = UseCentre ;
		  align->body     = UsePlanet ;
		  
		  StartWait() ;
		  alignments = LunarAlign( UseCentre ) ;
		  EndWait() ;


			  SendMessage(
			              GetDlgItem(hDlg,IDC_LIST1),
			              LB_RESETCONTENT,
						  0,
						  0L
						 ) ;

		  if (alignments > 0)
		  for ( i = 1 ; i <= alignments ; i++)
		  {
		  static char *Type[] = {"o-","o-o"} ;

			  sprintf(result,"%s      \t%s\t%s",
			                 Date_Time[UsePlanet][i]->aldate,
							 Date_Time[UsePlanet][i]->altime,
							 Type[Date_Time[UsePlanet][i]->conj]) ;


			  SendMessage(
			              GetDlgItem(hDlg,IDC_LIST1),
			              LB_ADDSTRING,
						  0,
						  (LPARAM)(LPCTSTR)result
						 ) ;
		  }

		EnableWindow(GetDlgItem(hDlg,IDC_UPDATE), FALSE) ;
		break ;

	case IDOK:
	EndDialog(hDlg,IDOK) ;
		break ;

	case IDCANCEL:
	EndDialog(hDlg,IDCANCEL) ;
		break ;

	default: break ;
	}

	default: break ;
  }
 return FALSE ;
}

void Aflag(HWND hDlg)
{
	EnableWindow(GetDlgItem(hDlg, IDC_UPDATE), TRUE) ;
}

/*****************************************
 Is a filename on a path?
 *****************************************/
int Fname_is_on_Path(char * path, char * fname)
{
	struct _finddata_t fi ;
	char pth[256] ;
// copy the path string to the search string
	strcpy(pth, path) ;
// append backslash if not there
	if (pth[strlen(pth) - 1] != '\\') strcat(pth, "\\") ;
// append the file name
	strcat(pth, fname) ;
// try to find the file name on the path
	if (_findfirst(pth, &fi) != -1L) return 1 ; // it's there
	return 0 ;									// it's not there
}

/******************************************************************
	Bud Data Collation Dialogue
*******************************************************************/

BOOL CALLBACK CollateDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static F1 = 1 ;
	static F2 = 0 ;

	switch(msg)
	{

case WM_INITDIALOG:
		SetDlgItemText(hDlg,IDC_GET_BUD_PREFIX,BudSearch->Prefix) ;
		SetDlgItemText(hDlg,IDC_GET_DAY1,      BudSearch->szBudDay1) ;
		SetDlgItemText(hDlg,IDC_GET_MONTH1,    BudSearch->szBudMon1) ;
		SetDlgItemText(hDlg,IDC_GET_YEAR1,     BudSearch->szBudYr1) ;
		SetDlgItemText(hDlg,IDC_GET_DAY2,      BudSearch->szBudDay2) ;
		SetDlgItemText(hDlg,IDC_GET_MONTH2,    BudSearch->szBudMon2) ;
		SetDlgItemText(hDlg,IDC_GET_YEAR2,     BudSearch->szBudYr2) ;

CheckDlgButton(hDlg,IDC_GET_PLAM,      ((SRCH & PLAM) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_GET_RLAM,      ((SRCH & RLAM) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_ON_DIAMETERS,  ((SRCH & LDIA) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_ON_RIGHT_RADII,((SRCH & LRYT) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_ON_LEFT_RADII, ((SRCH & LLFT) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_GET_MRDS,      ((SRCH & MRDS) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_GET_IPDS,      ((SRCH & IPDS) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_SAVE_COLLATION,((WantFile   ) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_ORDERINSET,    ((OrderInSet ) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_DAYOFMONTH,    ((DayOfMonth ) ? F1 : F2)) ;
CheckDlgButton(hDlg,IDC_BUD_ID,        ((UseBudID   ) ? F1 : F2)) ;

if (AskName)       CheckRadioButton(hDlg,IDC_DEFAULT_NAME,
									     IDC_ASK_NAME,
										 IDC_ASK_NAME) ;
else			   CheckRadioButton(hDlg,IDC_DEFAULT_NAME,
									     IDC_ASK_NAME,
										 IDC_DEFAULT_NAME) ;

//	return (TRUE) ;
	break ;

case WM_COMMAND:
	
	switch(LOWORD(wParam))
	{
	case IDOK:

		GetDlgItemText(hDlg,IDC_GET_BUD_PREFIX,BudSearch->Prefix,80) ;

		GetDlgItemText(hDlg,IDC_GET_DAY1,BudSearch->szBudDay1,80) ;
		BudSearch->BudDay1 = atoi(BudSearch->szBudDay1) ; 

		GetDlgItemText(hDlg,IDC_GET_MONTH1,BudSearch->szBudMon1,80) ;
		BudSearch->BudMon1 = atoi(BudSearch->szBudMon1) ;
		
		GetDlgItemText(hDlg,IDC_GET_YEAR1,BudSearch->szBudYr1,80) ;
		BudSearch->BudYr1 = atoi(BudSearch->szBudYr1) ;

		GetDlgItemText(hDlg,IDC_GET_DAY2,BudSearch->szBudDay2,80) ;
		BudSearch->BudDay2 = atoi(BudSearch->szBudDay2) ;

		GetDlgItemText(hDlg,IDC_GET_MONTH2,BudSearch->szBudMon2,80) ;
		BudSearch->BudMon2 = atoi(BudSearch->szBudDay2) ;

		GetDlgItemText(hDlg,IDC_GET_YEAR2,BudSearch->szBudYr2,80) ;
		BudSearch->BudYr2 = atoi(BudSearch->szBudYr2) ;

		if (IsDlgButtonChecked(hDlg, IDC_GET_PLAM))
			SRCH |= PLAM ; else SRCH &= ~PLAM ;
		if (IsDlgButtonChecked(hDlg, IDC_GET_RLAM))
			SRCH |= RLAM ; else SRCH &= ~RLAM ;
		if (IsDlgButtonChecked(hDlg, IDC_ON_DIAMETERS))
			SRCH |= LDIA ; else SRCH &= ~LDIA ;
		if (IsDlgButtonChecked(hDlg, IDC_ON_RIGHT_RADII))
			SRCH |= LRYT ; else SRCH &= ~LRYT ;
		if (IsDlgButtonChecked(hDlg, IDC_ON_LEFT_RADII))
			SRCH |= LLFT ; else SRCH &= ~LLFT ;
		if (IsDlgButtonChecked(hDlg, IDC_GET_MRDS))
			SRCH |= MRDS ; else SRCH &= ~MRDS ;
		if (IsDlgButtonChecked(hDlg, IDC_GET_IPDS))
			SRCH |= IPDS ; else SRCH &= ~IPDS ;
		if (IsDlgButtonChecked(hDlg, IDC_SAVE_COLLATION))
			     WantFile = 1 ; else      WantFile = 0 ;
		if (IsDlgButtonChecked(hDlg, IDC_ASK_NAME))
			      AskName = 1 ; else       AskName = 0 ;
		if (IsDlgButtonChecked(hDlg, IDC_ORDERINSET))
			   OrderInSet = 1 ; else    OrderInSet = 0 ;
		if (IsDlgButtonChecked(hDlg, IDC_DAYOFMONTH))
			   DayOfMonth = 1 ; else    DayOfMonth = 0 ;
		if (IsDlgButtonChecked(hDlg, IDC_BUD_ID))
			     UseBudID = 1 ; else      UseBudID = 0 ;

	EndDialog(hDlg,IDOK) ;
		break ;

	case IDCANCEL:
	EndDialog(hDlg,IDCANCEL) ;
		break ;
	
	case IDC_USE_PREFIX:
				 strcpy(BudSearch->Prefix,Bud_ID->Prefix) ;
				 strcpy(BudSearch->Suffix,Bud_ID->Suffix) ;
		SetDlgItemText(hDlg,IDC_GET_BUD_PREFIX,BudSearch->Prefix) ;
		break ;

	case IDC_USE_EPOCH1:
				 strcpy(BudSearch->szBudDay1,Bud_ID->szBudDay) ;
				 BudSearch->BudDay1 = atoi(BudSearch->szBudDay1) ;
		SetDlgItemText(hDlg,IDC_GET_DAY1,      BudSearch->szBudDay1) ;
				 strcpy(BudSearch->szBudMon1,Bud_ID->szBudMon) ;
				 BudSearch->BudMon1 = atoi(BudSearch->szBudMon1) ;
		SetDlgItemText(hDlg,IDC_GET_MONTH1,    BudSearch->szBudMon1) ;
				 strcpy(BudSearch->szBudYr1,Bud_ID->szBudYr) ;
				 BudSearch->BudYr1 = atoi(BudSearch->szBudYr1) ;
		SetDlgItemText(hDlg,IDC_GET_YEAR1,     BudSearch->szBudYr1) ;
		break ;

	case IDC_USE_EPOCH2:
				 strcpy(BudSearch->szBudDay2,Bud_ID->szBudDay) ;
				 BudSearch->BudDay2 = atoi(BudSearch->szBudDay2) ;
		SetDlgItemText(hDlg,IDC_GET_DAY2,      BudSearch->szBudDay2) ;
				 strcpy(BudSearch->szBudMon2,Bud_ID->szBudMon) ;
				 BudSearch->BudMon2 = atoi(BudSearch->szBudMon2) ;
		SetDlgItemText(hDlg,IDC_GET_MONTH2,    BudSearch->szBudMon2) ;
				 strcpy(BudSearch->szBudYr2,Bud_ID->szBudYr) ;
				 BudSearch->BudYr2 = atoi(BudSearch->szBudYr2) ;
		SetDlgItemText(hDlg,IDC_GET_YEAR2,     BudSearch->szBudYr2) ;
		break ;

	default:
		break ;
	}
	break ;
}
		return FALSE ;
}

// **************************
// Place item in a combo list
// **************************
void PutInCombo(HWND hDlg, int CB_ID, char * p)
{
	SendDlgItemMessage(hDlg,
						CB_ID,
						CB_ADDSTRING,
						(WPARAM)0,
						(LPARAM)(LPCTSTR)p) ;
}

// **************************
// Insert item in a combo list
// **************************
void InsInCombo(HWND hDlg, int CB_ID, char * p, int i)
{
	SendDlgItemMessage(hDlg,
						CB_ID,
						CB_INSERTSTRING,
						(WPARAM)i,
						(LPARAM)(LPCTSTR)p) ;
}

// **************************
// Place item in a combo edit box
// **************************
void PutCBEdBox(HWND hDlg, int CB_ID, char * p)
{
	SendDlgItemMessage(hDlg,
						CB_ID,
						WM_SETTEXT,
						(WPARAM)0,
						(LPARAM)(LPCTSTR)p) ;
}

// **************************
// Clear whole combo
// **************************
void ClearCombo(HWND hDlg, int CB_ID)
{
	SendDlgItemMessage(hDlg,
						CB_ID,
						CB_RESETCONTENT,
						(WPARAM)0,
						(LPARAM)0) ;
}

// **************************
// Get from combo
// **************************
int GetComboSel(HWND hDlg, int CB_ID)
{
	return (SendDlgItemMessage(hDlg,
						CB_ID,
						CB_GETCURSEL,
						(WPARAM)0,
						(LPARAM)0)) ;
}

// *************************************
// Load a Preview image
// *************************************
int OpenPreview(HWND hDlg, char * szPreview)
{
  HISSRC hSrc ;
     HDC hdc ;
	char ext[10] ;
	BYTE * pic ;

	strcpy(ext, GetExt(DropPath(szPreview))) ;

	if (!_stricmp(".BMP", ext))
	{

		hSrc = _ISOpenFileSource(szPreview) ;

			 hpic = _ISReadBMP
						(
						hSrc,
						&wPrview,
						&hPrview,
						24,
						NULL
						) ;

			   _ISCloseSource(hSrc) ;

	}

	if (!_stricmp(".JPG", ext))
	{

		hSrc = _ISOpenFileSource(szPreview) ;

			 hpic = _ISReadJPG
						(
						hSrc,
						&wPrview,
						&hPrview,
						24
						) ;

			   _ISCloseSource(hSrc) ;
	}

	pic = (BYTE *) hpic ;
	hdc = GetDC(hDlg) ;

	// Convert RGB buffer to ordinary DDB
	hPreview = _ISRGBToHBITMAP
				(
				pic,
				wPrview,
				hPrview,
				NULL,
				hdc
				) ;

	// finished with these
	ReleaseDC(hDlg, hdc) ;
	GlobalFree(hpic) ;

	return 1 ;
}

// *************************************
// Find all useable drives on the system
// including mapped Network drives
// *************************************
/******
int FindDrives( HWND hDlg )
{
	 int i, numdrives, curdrive,drvtyp ;
	char buff[100], drv[10] ;

// get the current drive
             curdrive = _getdrive() ;

for (i = 3, numdrives = 0 ; i <= 26 ; i++)  // there are 26 possibles, 24 leaving out the floppies.

if (!_chdrive(i)) // if we can switch to it, it exists.
			{

				sprintf(buff,"%c:", i + 'a' - 1) ;	// get the drive letter
				sprintf(drv, "%s\\", buff) ;		// select root
				drvtyp = GetDriveType(drv) ;		// get type of drive

				switch (drvtyp)
				{
				case DRIVE_FIXED: // allow in the list if hard, network or ramdisk drive
					DrvType[numdrives] = 0 ;
					SetWindowText(hDrv[numdrives], buff) ;
					EnableWindow(hDrv[numdrives++], TRUE) ; break ;
				case DRIVE_REMOTE:
					DrvType[numdrives] = 1 ;
					SetWindowText(hDrv[numdrives], buff) ;
					EnableWindow(hDrv[numdrives++], TRUE) ; break ;
				case DRIVE_RAMDISK:
					DrvType[numdrives] = 2 ;
					SetWindowText(hDrv[numdrives], buff) ;
					EnableWindow(hDrv[numdrives++], TRUE) ; break ;
				//case DRIVE_CDROM:
				//	DrvType[numdrives] = 4 ;
				//	SetWindowText(hDrv[numdrives], buff) ;
				//	EnableWindow(hDrv[numdrives++], TRUE) ; break ;
				default: break ;
				}
			}

// revert to current drive
_chdrive(curdrive) ;

	return numdrives ; // number of drives found
}
****/


// NB. the Get???ID() suite relies on results of a system scan

int GetPthID(
			 char * szpath,		// input, then output, string
			  int style			// if style, copy string to output
			)
{
	int i ;
	// compare incoming path strings with known path strings.
	// On match, return the global PTH ID. If style
	// asserted, return the PTH string in szpath.
	// If no match, return -1, and szpath unchanged.

	for (i = 0 ; i < A.iGpthIDs ; i++)	
	{
		if (!strcmp(szpath, A.szKnownpth[i]))
		{
		if (style) strcpy( szpath, A.szKnownpth[i]) ;
			return i ; // send home the global PTH ID 
		}
	}
		return -1 ; // if no PTH ID found/known
}

int GetImgID(
			 char * inst_name,	// input, then output, string
			  int style			// if style, copy string to output  
			)
{
	int i ;
	_strlwr(inst_name) ;
	// compare incoming prefix_epoch with prefix_epochs of
	// known IMGs. On match, return the global IMG ID. If
	// style asserted, return the IMG string in inst_name.
	// If no match, return -1 ;
	for (i = 0 ; i < A.iImgIDs ; i++)	
	{
		if (!strcmp(inst_name, _strlwr(DropExt(A.szKnownimg[i]))))
		{
		if (style) strcpy( inst_name, A.szKnownimg[i]) ;
			return i ; // send home the global IMG ID 
		}
	}
		return -1 ; // if no IMG found/known
}

int GetIniID(
			 char * inst_name,	// input, then output, string
			  int style			// if style, copy string to output  
			)
{
	int i ;
	_strlwr(inst_name) ;
	// compare incoming prefix_epoch with prefix_epochs of
	// known INIs. On match, return the global INI ID. If
	// style asserted, return the INI string in inst_name.
	// If no match, return -1 ;
	for (i = 0 ; i < A.iIniIDs ; i++)	
	{
		if (!strcmp(inst_name, _strlwr(DropExt(A.szKnownini[i]))))
		{
		if (style) strcpy( inst_name, A.szKnownini[i]) ;
			return i ; // send home the global INI ID 
		}
	}
		return -1 ; // if no INI found/known
}

int GetDatID(char * inst_name, int style)
{
	int i ;
	_strlwr(inst_name) ;
	// compare incoming prefix_epoch with prefix_epochs of
	// known DATs. On match, return the global DAT ID. If
	// style asserted, return the DAT string in inst_name.
	// If no match, return -1 ;
	for (i = 0 ; i < A.iDatIDs ; i++)
	{
		if (!strcmp(inst_name, _strlwr(DropExt(A.szKnowndat[i]))))
		{
		if (style) strcpy( inst_name, A.szKnowndat[i]) ;
			return i ; // send home the global DAT ID 
		}
	}
		return -1 ; // if no DAT found/known
}

int GetTrkID(char * inst_name, int style)
{
	int i ;
	_strlwr(inst_name) ;
	// compare incoming prefix_epoch with prefix_epochs of
	// known TRKs. On match, return the global TRK ID. If
	// style asserted, return the TRK string in inst_name.
	// If no match, return -1 ;
	for (i = 0 ; i < A.iTrkIDs ; i++)
	{
		if (!strcmp(inst_name, _strlwr(DropExt(A.szKnowntrk[i]))))
		{
		if (style) strcpy( inst_name, A.szKnowntrk[i]) ;
			return i ; // send home the global TRK ID 
		}
	}
		return -1 ; // if no TRK found/known
}

//********************************************
// Get depth of a path by counting backslashes
//********************************************
int GetDepth(char *p)
{
	int i, d ; i = d = 0 ; 
	while (p[i]) if (p[i++] == '\\') d++ ; // count backslashes
	return d - 1 ; // return the zero-based _index_ == (actual number - 1)
}

//*************************
// get IDs per image/instance
//*************************
void GetIDsperIMG( void )
{
	int i ;
				for (i = 0 ; i < A.iImgIDs ;  i++)
				{
					char target[50] ;
					int u, ID ;

					strcpy(target, DropExt(A.szKnownimg[i])) ;

					if ((ID = GetIniID(target, 0)) >= 0)
					{
						u = A.iNuminiperimg[i] ;
						A.iIniperimg[i][u] = ID ;
						A.iNuminiperimg[i]++ ;
						if (searching)
						SendMessage(hWndPB2, PBM_STEPIT, 0, 0) ;
					}

					if ((ID = GetDatID(target, 0)) >= 0)
					{
						u = A.iNumdatperimg[i] ;
						A.iDatperimg[i][u] = ID ;
						A.iNumdatperimg[i]++ ;
						if (searching)
						SendMessage(hWndPB2, PBM_STEPIT, 0, 0) ;
					}

					if ((ID = GetTrkID(target, 0)) >= 0)
					{
						u = A.iNumtrkperimg[i] ;
						A.iTrkperimg[i][u] = ID ;
						A.iNumtrkperimg[i]++ ;
						if (searching)
						SendMessage(hWndPB2, PBM_STEPIT, 0, 0) ;
					}
				}
}


//***************************
// Append a subdir to a path
//***************************
void GetNewPath(char *P, char *n, char *p)
{	int i ;	char c ; i = 0 ;
	while ((c = P[i]) != '*') p[i++] = c ; p[i] = '\0' ; // get rid of wild card
	strcat(p, n) ;	// concat new subdir name (but keep backslash)
}

//***********************************
// Is this path in the Working ABR?
//***********************************
int checkABR( int PID )
{

	if (strstr(A.szKnownpth[PID], szUsingArchive) == NULL)
	{
	A.pthinABR[PID] = 0 ;
		return 0 ;						// This path is NOT in the working ABR
	}
	else
	{
	A.pthinABR[PID] = 1 ;
		return 1 ;						// This path is in the working ABR
	}
}
//***********************
// double up backslashes
//***********************
char * DupSlash(char *a)  // double up contained backslashes
{
	 int i, j, len ;
	char b[256], c ;

		len = strlen(a) ;
		for ( i = 0, j = 0 ; i < len  ; i++ )	// copy string from a to b
			{
				c = b[j++] = a[i] ;
				if (c == '\\') { b[j++] = c ; }		// however, if a backslash found in a, immediately insert another in b
			}
		b[j] = '\0' ;

	return b ;
}


//****************************************
//  get the final component of a path
//****************************************
char * getlastcomp( char * p )
{
	 int i, j, f, len ;
	static char c, cmp[256] ;

	i = j = f = 0 ;
	// get rid of any trailing backslash on input string 
	if (p[(len = strlen(p)) - 1] == '\\') {f = 1 ; p[len - 1] = '\0' ;}
	
	while (p[i])
	{
	// on backslash, restart recording the component
	if ((c = p[i]) == '\\') j = 0 ; 
	*(cmp + j++) = c ;
	i++ ;
	}
	cmp[j] = '\0' ;
	if (f) strcat(cmp, "\\") ;

	// replace trailing backslash on input string
	if (p[strlen(p) - 1] != '\\') strcat(p, "\\") ;

	return cmp ;
}

//****************************************
// Is the first item known to the second?
//
// If the first item is a PTH, and the
// second is a PFX, then (typ) will give
// the file-type on the PTH in question. 
//****************************************
int   Is_A_known_to_B(
			int ID1,	//  first  ID
			int t1,		//  first TYP
			int ID2,	// second  ID
			int t2,		// second TYP
			int typ		// if first is PTH, and second is PFX, then typ gives the corresponding file type on the path
			)
{
	 int i, j, n, u,  sorted, newtail, tailID, Ok ;
	 int h ;
	char nstr[40], tail[256] ;

 if (t1 == IMG)		// 1st item is IMG
 {
	 switch(t2)		// what is the 2nd item?
	 {
	 case PFX: // 1st item is IMG, 2nd item is PFX. so is IMG known to PFX?
		 for ( i = Ok = 0, n = A.iNumImgperpfx[ID2]; i < n ; i++)
		 {
			 if (ID1 == A.Imgperpfx[ID2][i])
			 {
				 Ok = 1 ;
				 break ; // IMG ID already known to PFX ID
			 }
		 }
			if (!Ok) // IMG ID is new to PFX ID
			{
				// the count of images known to this prefix is the pending index
				u = A.iNumImgperpfx[ID2] ; // get it and use it
				// assign this index to this image ID
				A.Imgperpfx[ID2][u] = ID1 ;	// this is the image prefixed ID1 for the prefix indexed ID2
				// assign the actual epoch (not an ID) to prefix indexed ID2 as the ID1'th known to it
				A.fEpperpfx[ID2][u] = A.fKnownimgEp[ID1] ;
				// increment the number of images known to this prefix (new pending index & now the current count)
				A.iNumImgperpfx[ID2]++ ;		

			// sort image epochs and IDs into ascending order by epoch
				sorted = 0 ;
				while (!sorted)
				{
				 sorted = 1 ;
					for (i = 0 ; i < (A.iNumImgperpfx[ID2] - 1) ; i++)
					{
						double T ;
						   int iID ;
						if (A.fEpperpfx[ID2][i] > A.fEpperpfx[ID2][i + 1])
						{
												 T = A.fEpperpfx[ID2][i] ;
						   A.fEpperpfx[ID2][i]     = A.fEpperpfx[ID2][i + 1] ;
						   A.fEpperpfx[ID2][i + 1] = T  ;

											   iID = A.Imgperpfx[ID2][i] ;
						   A.Imgperpfx[ID2][i]     = A.Imgperpfx[ID2][i + 1] ;
						   A.Imgperpfx[ID2][i + 1] = iID ;

						 sorted = 0 ;
						}
					}
				}
					// get the earliest and latest epochs of the sequence
				        A.fEarlyEp[ID2] = A.fEpperpfx[ID2][0] ;  
					    A.fLaterEp[ID2] = A.fEpperpfx[ID2][u] ;
			}
		 break ;

	 case PTH: // 1st is IMG, 2nd is PTH.  so is IMG known to PTH?
						for( i = Ok = 0, n = A.iNumfiles[ID2] ; i < n ; i++)
						{
							if (A.iFileID[ID2][i] == ID1 && A.iFiletyp[ID2][i] == IMG)
							{
								Ok = 1 ; break ;
							}
						}
						if (!Ok) // record the index and type of the incoming file known to this path ID
						{
							// highest number of files of any type known to this PTH ID
						   u = A.iNumfiles[ID2] ;
						    // assign this image ID to this PTH ID as the highest index known to it
						    A.iFileID[ID2][u] = ID1 ;
							// assign file type against the same index 
						   A.iFiletyp[ID2][u] = IMG ;
						   // increment the number of files of any type known to this path 
						   A.iNumfiles[ID2]++ ;
						}
		 break ;
	 } // switch(t2)
 } // if (t1 == IMG)

 if (t1 == INI) // 1st Item is INI
 {
	 switch(t2)
	 {
	 case IMG: // 1st is INI, 2nd is IMG.  So is INI known to this IMG?
		 for ( i = Ok = 0, n = A.iNuminiperimg[ID2]; i < n ; i++)
		 {
			 {
			 if (ID1 == A.iIniperimg[ID2][i])
				{Ok = 1 ; break ;}
			 }
		 }
			if (!Ok) ;
			{
				u = A.iNuminiperimg[ID2] ;
				A.iIniperimg[ID2][u] = ID1 ;
				A.iNuminiperimg[ID2]++ ;
			}
		 break ;

	 case PFX: // 1st is INI, 2nd item is PFX.   So is INI known to PFX?
		 for ( i = Ok = 0, n = A.iNumIniperpfx[ID2]; i < n ; i++)
		 {
			 if (ID1 == A.Iniperpfx[ID2][i])	// This INI ID is already known to this PFX ID
			 {
				 Ok = 1 ;
				 break ;
			 }
		 }
			if (!Ok) // this INI ID is new to this PFX ID
			{	
				// highest index of INIs known to this prefix
				u = A.iNumIniperpfx[ID2] ;
				// assign this index to this PFX ID as the latest known to this PFX
				A.Iniperpfx[ID2][u] = ID1 ;
				// increment the number of INI IDs now known to this PFX
				A.iNumIniperpfx[ID2]++ ;
			}

		 break ;

	 case PTH: // 1st is INI, 2nd is PTH.       INI known to PTH?
						for( i = Ok = 0, n = A.iNumfiles[ID2] ; i < n ; i++)
						{
							if (A.iFileID[ID2][i] == ID1 && A.iFiletyp[ID2][i] == INI)
							{
								Ok = 1 ; break ; // This INI ID is already known to this PTH ID
							}
						}
						if (!Ok) // record the index and type of the incoming file known to this path ID
						{
						   u = A.iNumfiles[ID2] ;		// current number of files on this path (becomes index u)
						    A.iFileID[ID2][u] = ID1 ;	// the u'th file's ID
						   A.iFiletyp[ID2][u] = INI ;	// the type of the u'th file
						   A.iNumfiles[ID2]++ ;
						}

		 break ;
	 }  // switch (t2)
 } // if (t1 == INI)



if (useDATs)  // if we want to process "old" DAT files
{
 if (t1 == DAT)  // 1st Item is DAT
 {
	 switch(t2)
	 {
	 case IMG: // 1st is DAT, 2nd is IMG.  So is DAT known to this IMG?
		 for ( i = Ok = 0, n = A.iNumdatperimg[ID2]; i < n ; i++)
		 {
			 {
			 if (ID1 == A.iDatperimg[ID2][i])
				{Ok = 1 ; break ;}
			 }
		 }
			if (!Ok) ;
			{
				u = A.iNumdatperimg[ID2] ;
				A.iDatperimg[ID2][u] = ID1 ;
				A.iNumdatperimg[ID2]++ ;
			}
		 break ;

	 case PFX: // 1st is DAT, 2nd is PFX.  So is DAT known to PFX?
		 for ( i = Ok = 0, n = A.iNumDatperpfx[ID2]; i < n ; i++)
		 {
			 if (ID1 == A.Datperpfx[ID2][i])
			 {
				 {Ok = 1 ; break ;}
			 }
		 }
			if (!Ok)
			{
				u = A.iNumDatperpfx[ID2] ;
				A.Datperpfx[ID2][u] = ID1 ;
				A.iNumDatperpfx[ID2]++ ;
			}
		 break ;

	 case PTH: // 1st is DAT, 2nd is PTH.   So is DAT known to PTH?
						for( i = Ok = 0, n = A.iNumfiles[ID2] ; i < n ; i++)
						{
							if (A.iFileID[ID2][i] == ID1 && A.iFiletyp[ID2][i] == DAT)
							{
								Ok = 1 ; break ; // the file is known to the path
							}
						}
						if (!Ok) // the file is unknown to the path: record using the pending index
						{
						   u = A.iNumfiles[ID2] ;		//             the u'th (by index) file known to this path
						   A.iFileID[ID2][u] = ID1 ;	//   the ID of the u'th (by index) file known to this path
						   A.iFiletyp[ID2][u] = DAT ;	// the type of the u'th (by index) file known to this path
						   A.iNumfiles[ID2]++ ;			// the actual number of files now known, and the pending index
						}

		 break ;
	 } // switch (t2)
 } // if (t1 == DAT)
} // if (useDATs)

 if (t1 == TRK) // 1st Item is TRK
 {
	 switch(t2)
	 {
	 case IMG: // 1st is TRK, 2nd is IMG.   So is TRK known to IMG?
		 for ( i = Ok = 0, n = A.iNumtrkperimg[ID2]; i < n ; i++)
		 {
			 {
			 if (ID1 == A.iTrkperimg[ID2][i])
				{Ok = 1 ; break ;}
			 }
		 }
			if (!Ok) ;
			{
				u = A.iNumtrkperimg[ID2] ;
				A.iTrkperimg[ID2][u] = ID1 ;
				A.iNumtrkperimg[ID2]++ ;
			}
		 break ;

	 case PFX: // 1st is TRK, 2nd is PFX.   So is TRK known to PFX?
		 for ( i = Ok = 0, n = A.iNumTrkperpfx[ID2]; i < n ; i++)
		 {
			 {
			 if (ID1 == A.Trkperpfx[ID2][i])
				{Ok = 1 ; break ;}
			 }
		 }
			if (!Ok)
			{
				u = A.iNumTrkperpfx[ID2] ;
				A.Trkperpfx[ID2][u] = ID1 ;
				A.iNumTrkperpfx[ID2]++ ;
			}
		 break ;

	 case PTH: // 1st is TRK, 2nd is PTH.   So is TRK known to PTH?
						for( i = Ok = 0, n = A.iNumfiles[ID2] ; i < n ; i++)
						{
							if (A.iFileID[ID2][i] == ID1 && A.iFiletyp[ID2][i] == TRK)
							{
								Ok = 1 ; break ;
							}
						}
						if (!Ok)
						{
						   u = A.iNumfiles[ID2] ;
						    A.iFileID[ID2][u] = ID1 ;
						   A.iFiletyp[ID2][u] = TRK ;
						   A.iNumfiles[ID2]++ ;
						}
		 break ;
	 }  // switch (t2)
 }  // if (t1 == TRK)

 if (t1 == PTH) // 1st item is PTH:
 {
	 switch(t2)
	 {
//**********************************************************
	// Are item paths known to the item prefixes?
//**********************************************************
	 case PFX:	// 1st is PTH, 2nd is PFX.  Is PTH known to PFX?
				//(The file-type on the path is given by typ.)

	 // Any (PTH-to-an-item) new to a PFX is also a new item-series, surely?


	 // If so, item series and item paths per PFX are synonymous and there
	 // is no need to maintain a seperate record of series per PFX.


		 switch(typ) // what is the type of item on the path?
		 {
//~~~~~~~~~~~~~
		 case IMG: // is IMG PTH known to PFX?
		 for ( i = Ok = 0, n = A.iNumimgpthsperpfx[ID2] ; i < n ; i++)
		 {
			 if (ID1 == A.iImgpthperpfx[ID2][i])
			 { Ok = 1 ; break ; }
		 }
		 if (!Ok) // path to IMG new to prefix
		 {
			 /***
			 if (checkABR(ID1))				// is this path in the working ABR?
			 {
				LPSUITE ps ; // pS ;
				   char str[256] ;
			***/

			 u = A.iNumimgpthsperpfx[ID2] ;		// record the IMG path against the prefix
			 A.iImgpthperpfx[ID2][u] = ID1 ;
			 A.iNumimgpthsperpfx[ID2]++ ;
/***
			// get the trailing ("tail") component of the path to the item.
			// it is common across the suite pertaining to this path.
			strcpy(tail, getlastcomp(A.szKnownpth[ID1])) ;

					// is this tail new to the pfx?
					// presume it's not, then see if it is
					for (j = Ok = newtail = 0, n = A.iTails ; j < n ; j++)
					{
						if (!strcmp(A.szKnowntail[j], tail))
						{
							Ok = 1 ;
							tailID = j ;	// tail has been seen, and it's this one
							break ;		
						}
					}
					if (!Ok)				// tail is new
					{
						char * t ;
						t = (char *)GlobalAlloc(GPTR, (strlen(tail) + 2) * sizeof(char)) ;
						strcpy(t, tail) ;
						u = tailID = A.iTails ;			// new tail, and it's this one
						A.szKnowntail[u] = t ;			// this is its string
						A.iTails++ ;					// bump number of known tails
						newtail = 1 ;					// flag tail as new
					}

				   strcpy(str, A.szKnowntail[tailID]) ;

				   if (newtail) // this is the first sight of the incoming tail
				   {
					   // so we want a new suite to contain the incoming IMG PTH
					   // and possibly other paths later
					   ps = (LPSUITE)GlobalAlloc(GPTR, sizeof(SUITE)) ;		// make room
					   ps = MakeSuite(str, ID1, -1, -1, -1, ps) ;	// create suite with IMG PTH installed
					    A.Suitepertail[tailID] = ps ;				// put this suite into memory

					   u = A.iNumsuiperpfx[ID2] ;						// this is also a new suite to the pfx
					   A.pSuiteperpfx[ID2][u] = ps ;				// tell the pfx about it
					   A.iNumsuiperpfx[ID2]++ ;						// and sequence the suite wrt the pfx
					   iSuites++ ;									// bump the total number of suites
				   }

				   // OK, we've seen this tail, and there should a
				   // suite for it, with one or more paths of some kind installed.

					   ps = A.Suitepertail[tailID] ;
					   if ((ps->iIMGpth) < 0)			// if the IMG path is not installed,
						    ps->iIMGpth = ID1 ;			// install it now

							h = A.iNumsuiperpfx[ID2] - 1 ;

								_itoa(iSuites, nstr, 10) ;
								strcat(nstr, " Suites") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_SUITECOUNT), nstr) ;
								SetWindowText(GetDlgItem(  hArcDlg, IDC_S_SUITE),       str) ;

						InsInCombo(hDlgSource, IDC_CB_SUITES, str, h) ;
			 }
		***/
		 }
			 break ; // case IMG: PTH to IMG is known to PFX
//~~~~~~~~~~~~~
		 case INI: // is INI PTH known to PFX?
		 for ( i = Ok = 0, n = A.iNuminipthsperpfx[ID2] ; i < n ; i++)
		 {
			 if (ID1 == A.iInipthperpfx[ID2][i])
			 { Ok = 1 ; break ; }
		 }
		 if (!Ok) // this path to INI is new to this prefix
		 {
			 if (checkABR(ID1))				// is this path in the working ABR?
			 {
				LPSUITE ps ; // pS ;
				   char str[256] ;

			 u = A.iNuminipthsperpfx[ID2] ;		// record the INI path against the prefix
			 A.iInipthperpfx[ID2][u] = ID1 ;
			 A.iNuminipthsperpfx[ID2]++ ;

			// get the trailing ("tail") component of the path to the item.
			// it is common across the suite pertaining to this path.
			strcpy(tail, getlastcomp(A.szKnownpth[ID1])) ;

					// is this tail new to the pfx?
					// presume it's not, then see if it is
					for (j = Ok = newtail = 0, n = A.iTails ; j < n ; j++)
					{
						if (!strcmp(A.szKnowntail[j], tail))
						{
							Ok = 1 ;
							tailID = j ;	// tail has been seen, and it's this one
							break ;		
						}
					}
					if (!Ok)				// tail is new
					{
						char * t ;
						t = (char *)GlobalAlloc(GPTR, (strlen(tail) + 2) * sizeof(char)) ;
						strcpy(t, tail) ;
						u = tailID = A.iTails ;			// new tail, and it's this one
						A.szKnowntail[u] = t ;			// this is its string
						A.iTails++ ;					// bump number of known tails
						newtail = 1 ;					// flag tail as new
					}

				   strcpy(str, A.szKnowntail[tailID]) ;

				   if (newtail) // this is the first sight of the incoming tail
				   {
					   // so we want a new suite to contain the incoming INI PTH
					   // and possibly other paths later
					   ps = (LPSUITE)GlobalAlloc(GPTR, sizeof(SUITE)) ;		// make room
					   ps = MakeSuite(str, 0, ID1, -1, -1, ps) ;	// create suite with INI PTH installed
					    A.Suitepertail[tailID] = ps ;				// put this suite into memory

					   u = A.iNumsuiperpfx[ID2] ;						// this is also a new suite to the pfx
					   A.pSuiteperpfx[ID2][u] = ps ;				// tell the pfx about it
					   A.iNumsuiperpfx[ID2]++ ;						// and sequence the suite wrt the pfx
					   iSuites++ ;									// bump the total number of suites
				   }

				   // OK, we've seen this tail, and there should a
				   // suite for it, with one or more paths of some kind installed.

					   ps = A.Suitepertail[tailID] ;
					   if ((ps->iINIpth) < 0)			// if the INI path is not installed,
						    ps->iINIpth = ID1 ;			// install it now

					   /****
					   if ((ps->iIMGpth <= 0)			// if the IMG path is not installed
					   {
					   // does this INI have a record of
					   // the pertaining image's path?

					   gpps() ;

					   // if it does, get it, and check that the image is
					   // actually still where it says it is,
					   // if it is, get the image's global path ID,
					   // and install it in the suite now.
					   // if it is not, then it has been
					   // deleted or moved or not recorded
					   // in the INI. Put out an alert!
					   }
					   ****/


							h = A.iNumsuiperpfx[ID2] - 1 ;

								_itoa(iSuites, nstr, 10) ;
								strcat(nstr, " Suites") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_SUITECOUNT), nstr) ;
								//SetWindowText(GetDlgItem(  hArcDlg, IDC_S_SUITE),       str) ;

						InsInCombo(hDlgSource, IDC_CB_SUITES, str, h) ;
			 }
		 }

			 break ; // case INI: PTH to INI is known to PFX

//~~~~~~~~~~~~~
		 case DAT: // is DAT PTH known to PFX?

			 if (!useDATs) break ; // just break out

		 for ( i = Ok = 0, n = A.iNumdatpthsperpfx[ID2] ; i < n ; i++)
		 {
			 if (ID1 == A.iDatpthperpfx[ID2][i])
			 {
				 Ok = 1 ; break ;
			 }
		 }
		 if (!Ok) // path to DAT new to prefix
		 {
			 if (checkABR(ID1))			// is this path in the working ABR?
			 {
				LPSUITE ps ;
				   char str[256] ;

			 u = A.iNumdatpthsperpfx[ID2] ;
			 A.iDatpthperpfx[ID2][u] = ID1 ;
			 A.iNumdatpthsperpfx[ID2]++ ;

			// get the last component of the path to the item.
			// it is common across the suite pertaining to this path.

					strcpy(tail, getlastcomp(A.szKnownpth[ID1])) ;

					// is this tail new to the pfx?
					// presume it's not, then see if it is
					for (j = Ok = newtail = 0, n = A.iTails ; j < n ; j++)
					{
						if (!strcmp(A.szKnowntail[j], tail))
						{
							Ok = 1 ;
							tailID = j ;	// tail has been seen, and it's this one
							break ;		
						}
					}
					if (!Ok)				// tail is new
					{
						char * t ;
						t = (char *)GlobalAlloc(GPTR, (strlen(tail) + 2) * sizeof(char)) ;
						strcpy(t, tail) ;
						u = tailID = A.iTails ;			// new tail, and it's this one
						A.szKnowntail[u] = t ;			// this is its string
						A.iTails++ ;					// bump number of known tails
						newtail = 1 ;					// flag tail as new
					}

				   strcpy(str, A.szKnowntail[tailID]) ;

				   if (newtail) // this is the first sight of the incoming tail
				   {
					   // so we want a new suite to contain the incoming DAT PTH
					   // and possibly other paths later
					   ps = (LPSUITE)GlobalAlloc(GPTR, sizeof(SUITE)) ;		// make room
					   ps = MakeSuite(str, 0, -1, ID1, -1, ps) ;	// create suite with DAT PTH installed
					   A.Suitepertail[tailID] = ps ;				// put this suite into memory

					   u = A.iNumsuiperpfx[ID2] ;					// this is also a new suite to the pfx
					   A.pSuiteperpfx[ID2][u] = ps ;				// tell the pfx about it
					   A.iNumsuiperpfx[ID2]++ ;						// and sequence the suite wrt the pfx
					   iSuites++ ;									// bump the total number of suites
				   }

				   // OK, we've seen this tail, and there should be a
				   // suite for it, with one or more paths of some kind installed.

					   ps = A.Suitepertail[tailID] ;
					   if ((ps->iDATpth) < 0)			// if the DAT path is not installed,
						    ps->iDATpth = ID1 ;			// install it

							h = A.iNumsuiperpfx[ID2] - 1 ;

								_itoa(iSuites, nstr, 10) ;
								strcat(nstr, " Suites") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_SUITECOUNT), nstr) ;

						InsInCombo(hDlgSource, IDC_CB_SUITES, str, h) ;
			 }
		 }
			 break ; // case DAT: PTH to DAT is known to PFX
//~~~~~~~~~~~~~
		 case TRK: // is TRK PTH known to PFX?
		 for ( i = Ok = 0, n = A.iNumtrkpthsperpfx[ID2] ; i < n ; i++)
		 {
			 if (ID1 == A.iTrkpthperpfx[ID2][i])
			 {
				 Ok = 1 ; break ;
			 }
		 }
		 if (!Ok) // path to TRK new to prefix (TRK path string is available now) 
		 {
			 if (checkABR(ID1))	// is this path in the working ABR?
			 {
				LPSUITE ps ;
				   char str[256] ;

			 u = A.iNumtrkpthsperpfx[ID2] ;
			 A.iTrkpthperpfx[ID2][u] = ID1 ;
			 A.iNumtrkpthsperpfx[ID2]++ ;

			// get the last component of the path to the item.
			// it is common to the suites pertaining to this path.

					strcpy(tail, getlastcomp(A.szKnownpth[ID1])) ;

					// is this tail new to the pfx?
					// presume it's not, then see if it is
					for (j = Ok = newtail = 0, n = A.iTails ; j < n ; j++)
					{
						if (!strcmp(A.szKnowntail[j], tail))
						{
							Ok = 1 ;
							tailID = j ;	// tail has been seen, and it's this one
							break ;		
						}
					}
					if (!Ok)				// tail is new
					{
						char * t ;
						t = (char *)GlobalAlloc(GPTR, (strlen(tail) + 2) * sizeof(char)) ;
						strcpy(t, tail) ;
						u = tailID = A.iTails ;			// new tail, and it's this one
						A.szKnowntail[u] = t ;			// this is its string
						A.iTails++ ;					// bump number of known tails
						newtail = 1 ;					// flag tail as new
					}

				   strcpy(str, A.szKnowntail[tailID]) ;

				   if (newtail) // this is the first sight of the incoming tail
				   {
					   // so we want a new suite to contain the incoming TRK PTH
					   // and possibly other paths later
					   ps = (LPSUITE)GlobalAlloc(GPTR, sizeof(SUITE)) ;		// make room
					   ps = MakeSuite(str, 0, -1, -1, ID1, ps) ;	// create suite with TRK PTH installed
					    A.Suitepertail[tailID] = ps ;				// put this suite into memory

					   u = A.iNumsuiperpfx[ID2] ;					// this is also a new suite to the pfx
					    A.pSuiteperpfx[ID2][u] = ps ;				// tell the pfx about it
					   A.iNumsuiperpfx[ID2]++ ;						// and sequence the suite wrt the pfx
					   iSuites++ ;									// bump the total number of suites
				   }

				   // OK, we've seen this tail, and there should be a
				   // suite for it, with one or more paths of some kind installed.

					   ps = A.Suitepertail[tailID] ;
					   if ((ps->iTRKpth) < 0)			// if the TRK path is not installed,
						    ps->iTRKpth = ID1 ;			// install it

							h = A.iNumsuiperpfx[ID2] - 1 ;

								_itoa(iSuites, nstr, 10) ;
								strcat(nstr, " Suites") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_SUITECOUNT), nstr) ;
						InsInCombo(hDlgSource, IDC_CB_SUITES, str, h) ;
			 }
		 }
			 break ; // case TRK: PTH to TRK is known to PFX

		 } // switch (typ)

		 break ; // case PFX: The item-path is known to PFX

//**********************************************************
	// Are item paths known to the items?
//**********************************************************

	 case IMG: // 1st is PTH, 2nd is IMG.  is PTH known to IMG?
		 for ( i = Ok = 0, n = A.iNumpthsperimg[ID2]; i < n ; i++)
		 {
			 if (ID1 == A.iPthIDperimg[ID2][i])
			 {Ok = 1 ; break ;}
		 }
			  if (!Ok) // PTH new to IMG
			  {
				 u = A.iNumpthsperimg[ID2] ;
				 A.iPthIDperimg[ID2][u] = ID1 ;
				 A.iNumpthsperimg[ID2]++ ;
			  }
		 break ; // case IMG : PTH is known to IMG

	 case INI: // 1st is PTH, 2nd is INI.   is PTH known to INI?
		 for ( i = Ok = 0, n = A.iNumpthsperini[ID2]; i < n ; i++)
		 {
			 if (ID1 == A.iPthIDperini[ID2][i])
			 { Ok = 1 ; break ; }
		 }
			 if (!Ok)
			 {
				 u = A.iNumpthsperini[ID2] ;
				 A.iPthIDperini[ID2][u] = ID1 ;
				 A.iNumpthsperini[ID2]++ ;
			 }

		 break ; // case INI : PTH is known to INI

 	 case DAT: // 1st is PTH, 2nd is DAT.   is PTH known to DAT?

		 if (!useDATs) break ;

		 for ( i = Ok = 0, n = A.iNumpthsperdat[ID2]; i < n ; i++)
		 {
			 if (ID1 == A.iPthIDperdat[ID2][i])
			 { Ok = 1 ; break ; }
		 }
			 if (!Ok)
			 {
				 u = A.iNumpthsperdat[ID2] ;
				 A.iPthIDperdat[ID2][u] = ID1 ;
				 A.iNumpthsperdat[ID2]++ ;
			}
		 break ; // case DAT : PTH is known to DAT

	 case TRK: // 1st is PTH, 2nd is TRK.   is PTH known to TRK?
		 for ( i = Ok = 0, n = A.iNumpthspertrk[ID2]; i < n ; i++)
		 {
			 if (ID1 == A.iPthIDpertrk[ID2][i])
			 { Ok = 1 ; break ; }
		 }
			 if (!Ok) // PTH is new to TRK 
			 {
				 u = A.iNumpthspertrk[ID2] ;
				 A.iPthIDpertrk[ID2][u] = ID1 ;
				 A.iNumpthspertrk[ID2]++ ;
			 }

		 break ; // case TRK : PTH is known to TRK
	 }  //switch (t2)
 } // if (t1 == PTH)

	return 1 ;
} // Is_A_known_to_B()

// ********************************************************
// *************** InspectFile() **************************
//	accepts a pointer to a path, and to a file name.
//  checks for the validity of the file
//
//  if valid and new, the file is incorporated into the working
//  (in-session) archive.
//
//  Called by MaybeHere() during a system search
//
//	Calls Is_A_known_to_B() to establish associations
//
  // On every pass through this function, the features of a valid file are noted
   // and recorded in the "working (in-session) archive".
   // 
   //		Since items are recorded in the order in which they are found,
   //		there is no guarantee that that order will match the historical
   //		order of their developments, or of their associations during 
   //		development, though non-image items with the same prefix and
   //		type on the same path are likely to belong together.
   //
   //	A possible solution to this difficulty would be to record an "assay number" against
   //	every working (assay) of an instance, though this would only work for new assays.
 // ********************************************************
int InspectFile(HWND hDlg, char * p, char * fname)
{
 UINT typ, n, j, u ;
 static UINT eposeen, pfxseen, imgseen, iniseen, datseen, trkseen, pathseen, ok ;
 static UINT FID ;
   UINT inipth = 0 ;
   UINT datpth = 0 ;
   UINT trkpth = 0 ;
  //int h ;
 double jep ;
   char pfx[100] ;
   char pth[256] ;
   char nstr[80] ;
   char * s ;

/*++ a copy for easy reference
typedef struct tagbudfile
	{
		  char szfilename[100] ;	// the valid file name
		  char     prefix[ 50] ;	// the prefix pertaining to the valid file
		  char     szpath[256] ;	// the path string to the valid file 
		double epoch ;				// the epoch of the valid file
		 ULONG  bref ;				// the index of this reference
		  UINT   typ ;				// the type of the valid file (IMG, INI, DAT or TRK)
		  UINT pfxID ;				// the prefix ID
		  UINT typID ;				// the ID corresponding to the type
		  UINT pthID ;				// the path ID

	} BUDFILE, * LPBUDFILE ;

LPBUDFILE Bfiles[MAXITEM] ;
--*/
  
						typ = 0 ; // presume incoming invalid
	
					 if (typ = ParseBudID(fname, &Valid_Bud))  // but is it?
					 {
						 // incoming is valid.
						 budref++ ;
						 jep = Valid_Bud.JulEp ;			// its epoch
						 strcpy(pfx, Valid_Bud.Prefix) ;	// the prefix string
						 strcpy(pth, p) ;					// the file's path
						 // if no trailing backslash, provide one
						 if (pth[strlen(pth) - 1] != '\\')	 strcat(pth,"\\") ;


					// Prefix

						// check if prefix of the file is known, whatever the file's epoch or type
						 for (j = pfxseen = 0, n = A.iPfxIDs ; j < n ; j++)
						 {
							 if (!strcmp(pfx, A.szKnownpfx[j]))
							 {
								 pfxseen = 1 ; iPfxID = I.pfxID = j ;
								 break ;
							 }
						 } // is seen prefix
						 if (!pfxseen)	// is new prefix
						 {
							 s = (char *)GlobalAlloc(GPTR, (strlen(pfx)+2) * sizeof(char)) ;
							 strcpy(s, pfx) ;
							 u = iPfxID = I.pfxID = A.iPfxIDs ; // use pending ID
							 A.szKnownpfx[u] = s ;	  // global prefix string
							 A.iPfxIDs++ ;			  // next pending ID and current prefix count
							// report
							 strcpy(nstr, _itoa(A.iPfxIDs, nstr,10)) ;
							 strcat(nstr, " Prefixes") ;
							 SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_PREFIXES), nstr) ;
						 }
						 // have prefix, old or new

					// Path

						// the path of the file, whatever its prefix,epoch or type
						for (j = pathseen = 0, n = A.iGpthIDs ; j < n ; j++)
						 {
							 if (!strcmp(A.szKnownpth[j], pth))
							 { 
								 iGpthID = j ; pathseen = 1 ;
								 break ;		// seen path
							 }
						 }// is seen path
						 if (!pathseen)	// is new path
						 {
							 s = (char *)GlobalAlloc(GPTR, (strlen(pth)+2) * sizeof(char)) ;
							 strcpy(s, pth) ;
							 u = iGpthID = A.iGpthIDs ;			// use pending global path ID
							 A.szKnownpth[u] = s ;				// index the path string against the path ID
							 incpth("InspectFile(): new path")  ; // A.iGpthIDs++ ; (next pending Global path ID and count)
							 _itoa(A.iGpthIDs, nstr, 10) ;
							 strcat(nstr, " Paths") ;
							 SetWindowText(GetDlgItem(hDlgStats, IDC_S_PATHCOUNT), nstr) ;
						 }

					// Type

						switch (typ) // type dependency
						 {
				case IMG: // incoming IMG
						 for (j = imgseen = 0, n = A.iImgIDs ; j < n ; j++)
						 {
							 if (!strcmp(fname, A.szKnownimg[j])) // the image is known
							 {
								 imgseen = 1 ; iImgID = j ;
								 break ;
							 }
						 }	// is seen IMG
						 if (!imgseen) // is new IMG
						 {
						  char * d, instdate[100] ;
							 s = (char *)GlobalAlloc(GPTR, (strlen(fname)+2) * sizeof(char)) ; // update image records
							 strcpy(s, fname) ;
							 u = iImgID = A.iImgIDs ;			// use pending global Image ID
							 A.szKnownimg[u] = s ;				// index the Image string by its now current Image ID
							A.fKnownimgEp[u] = ep = jep ;		// index the Image epoch  by its now current Image ID
							civildate() ;						// expand the epoch
							calendar() ;						// get equivalent epoch string
							sprintf(instdate, "%s  %s", dayt, Valid_Bud.szTime) ;	
							d = (char *)GlobalAlloc(
								GPTR, (strlen(instdate) + 2) * sizeof(char)) ; // allocate for epoch string
							strcpy(d, instdate) ;				// copy epoch string into allocated memory
							A.szImgdate[u] = d ;				// index  date string against global Image ID
							A.iInstYear[u] = Valid_Bud.BudYr ;	// index  year against global Image ID
						   A.iInstMonth[u] = Valid_Bud.BudMon ;	// index month against global Image ID
						     A.iInstDay[u] = Valid_Bud.BudDay ; // etcetera
						    A.iInstHour[u] = Valid_Bud.BudHr ;
						  A.iInstMinute[u] = Valid_Bud.BudMn ;
						  A.iInstSecond[u] = Valid_Bud.BudSc ;
						    A.iImgPfxID[u] = iPfxID ;			// index prefix ID against Image ID
							 A.iImgIDs++ ;						// next pending Image ID and now current count of Images
							 // report
							 _itoa(A.iImgIDs, nstr, 10) ;		// count of Images as string
							 strcat(nstr, " Images") ;
							 SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_INSTANCES), nstr) ;
						 }
						 // have global image, its pfx, its path, & its epoch
						 // the image is known to its epoch

						 // is img known to pfx?
						 Is_A_known_to_B(iImgID,  IMG, iPfxID,  PFX, typ) ;
						 // is image path known to prefix?
						 Is_A_known_to_B(iGpthID, PTH, iPfxID,  PFX, typ) ;
						 // is img known to its path?
						 Is_A_known_to_B(iImgID,  IMG, iGpthID, PTH, typ) ;
						 // is the image path known to the image?
						 Is_A_known_to_B(iGpthID, PTH, iImgID,  IMG, typ) ;
							 break ;

				case INI:	// incoming INI
						 for (j = iniseen = 0, n = A.iIniIDs ; j < n ; j++)
						 {
							if (!strcmp(fname, A.szKnownini[j]))
							{
								iniseen = 1 ;
								iIniID = j ;
								break ;
							}
						 }	// seen INI
						 if (!iniseen)	// new INI
						 {
							 s = (char *)GlobalAlloc(GPTR, (strlen(fname)+2) * sizeof(char)) ; // allocate for name string
							 strcpy(s, fname) ;						// copy ini name string to allocated memory
										  u  = iIniID = A.iIniIDs ; // pending global iniID used now
							 A.szKnownini[u] = s ;					// iniID-indexed pointer to ini name string
							  A.iIniPfxID[u] = iPfxID ;				// the corresponding prefix ID
							  A.iIniIDs++ ;							// new pending global iniID is also count of INIs
							  _itoa(A.iIniIDs, nstr,10) ;			// count of INIs as string
							  // report
							 strcat(nstr, " INIs") ;
							 SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_INIS), nstr) ; // report INI count
						 }
						 // is ini known to pfx?
						 Is_A_known_to_B(iIniID,   INI, iPfxID,  PFX, typ) ;
						 // is ini path known to pfx?
						 Is_A_known_to_B(iGpthID,  PTH, iPfxID,  PFX, typ) ;
						 // is ini known to path?
						 Is_A_known_to_B(iIniID,   INI, iGpthID, PTH, typ) ;
						 // is path known to ini?
						 Is_A_known_to_B(iGpthID,  PTH, iIniID,  INI, typ) ;

						 // have global ini, its pfx, & its epoch
						 // the ini is known to its epoch

							 break ;

				case DAT:	// incoming DAT

					if (!useDATs) break ;  // not using "old" DATs

						 for (j = datseen = 0, n = A.iDatIDs ; j < n ; j++)
						 {
							 if (!strcmp(fname, A.szKnowndat[j]))
							 {
								 datseen = 1 ; // DAT globally known
								 I.datID = iDatID = j ;
								 break ;		// seen DAT
							 }
						 }
						 if (!datseen)	// new DAT, unknown generally and to epoch specifically
						 {
							 s = (char *)GlobalAlloc(GPTR, (strlen(fname)+2) * sizeof(char)) ;
							 strcpy(s, fname) ;
							 u = I.datID = iDatID = A.iDatIDs ;
							 A.szKnowndat[u] = s ;
							  A.iDatPfxID[u] = iPfxID ;
							  A.iDatIDs++ ;
							 _itoa(A.iDatIDs, nstr,10) ;
							 strcat(nstr, " DATs") ;
							 SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_DATS), nstr) ;
						 }
						 // is dat known to pfx?
						 Is_A_known_to_B(iDatID,   DAT, iPfxID,  PFX, typ) ;
						 // is dat path known to pfx?
						 Is_A_known_to_B(iGpthID,  PTH, iPfxID,  PFX, typ) ;
						 // is dat known to path?
						 Is_A_known_to_B(iDatID,   DAT, iGpthID, PTH, typ) ;
						 // is path known to dat?
						 Is_A_known_to_B(iGpthID,  PTH, iDatID,  DAT, typ) ;
						 
						 // have global dat, its pfx & its epoch & its path
							 break ;

				case TRK:	// incoming TRK
						for (j = trkseen = 0, n = A.iTrkIDs ; j < n ; j++)
						 {
							 if (!strcmp(fname, A.szKnowntrk[j]))
							 {
								 trkseen = 1 ;
								 I.trkID = iTrkID = j ;
								 break ;		// seen TRK
							 }
						 }
						 if (!trkseen)	// new TRK
						 {
							 s = (char *)GlobalAlloc(GPTR, (strlen(fname)+2) * sizeof(char)) ;
							 strcpy(s, fname) ;
							 u = I.trkID = iTrkID = A.iTrkIDs ;
							 A.szKnowntrk[u] = s ;
							  A.iTrkPfxID[u] = iPfxID ;
							  A.iTrkIDs++ ;
							 _itoa(A.iTrkIDs, nstr,10) ;
							 strcat(nstr, " TRKs") ;
							 SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_TRKS), nstr) ;
						 }
						 // is trk known to pfx?
						 Is_A_known_to_B(iTrkID,  TRK, iPfxID,  PFX, typ) ;
						 // is trk path known to pfx?
						 Is_A_known_to_B(iGpthID, PTH, iPfxID,  PFX, typ) ;
						 // is trk known to path?
						 Is_A_known_to_B(iTrkID,  TRK, iGpthID, PTH, typ) ;
						 // is path known to trk?
						 Is_A_known_to_B(iGpthID, PTH, iTrkID,  TRK, typ) ;
						
						 // have global trk, its pfx & its epoch
								break ;

						 default: break ;
						} // switch(typ)

						 if (!searched)
						 {
						 // progress bar
						 SendMessage(hWndPB3, PBM_STEPIT, 0, 0) ;
						 }
						 // flash report
						 //SetWindowText(GetDlgItem(hDlg, IDC_S_FOUND), fname) ;
						 }
					 
	return typ ;

} // InspectFile()

/*****************************************************************************
	Inspect a directory for the presence of a file of a valid extension
	containing an embedded underscore in the file name, and if one is found,
	by noting the directory's depth and index, identify that directory as a
	place to be fully searched for valid files.  This allows full searches
	to be performed in specified type order, so that associations may be found.
 *****************************************************************************/
int InspectDirs(
			int t,	// type to find
			int d,	// directory depth
			int n	// directory index at depth
		    ) 
{
  struct _finddata_t  hi ;
				char  filefind[256] ;
				long  h ;
				 int  Ok ;
				UINT  *s ;

// specifiable file types                  type-index
 static char * findtyp[] = {"\\*_*.jpg",	// 0 
							"\\*_*.bmp",	// 1
							"\\*_*.ini",	// 2
							"\\*_*.dat",	// 3
							"\\*_*.trk"} ;	// 4

			 Ok = 0 ;								// presume none found
			 strcpy(filefind, szDirpath[d][n]) ;	// form search target 
			 strcat(filefind, findtyp[t]) ;			// form search target
			 
			 if ((h = _findfirst(filefind, &hi)) != -1L)	// seek first
			 {
				 Ok = 1 ;	// have found a file of the specified type in this directory

					switch(t)
					{
					case 0:										// jpg
					case 1:	s = &iImgDirs ;						// bmp
						    iImgDirDepth[*s] = d ;
							iImgDirIndex[*s] = n ; 
													break ;

					case 2:	s = &iIniDirs ;						// ini
						    iIniDirDepth[*s] = d ;
							iIniDirIndex[*s] = n ; 
													break ;

					case 3: if (!useDATs)			break ;
							s = &iDatDirs ;						// dat
						    iDatDirDepth[*s] = d ;
							iDatDirIndex[*s] = n ; 
													break ;
					case 4: s = &iTrkDirs ;						// trk
							iTrkDirDepth[*s] = d ;
							iTrkDirIndex[*s] = n ; 
													break ;
					}
					++(*s) ;
			 }
			 _findclose(h) ;
			 return Ok ; // return 1 on finds, 0 on no finds
}

//**************************************************
//					MaybeHere()
//
// Find all files of a given type on a given path.
//
// MaybeHere() calls InspectFile() to check found files
// for validity. InspectFile() in turn calls Is_A_known_to_B()
// on valid files, to incorparate new files into the
// working archive, and to detect suites.  
//**************************************************
int MaybeHere(
			HWND hDlg,
			char *p,		// path to inspect
			 int t			// file type to seek for on the path
		   )
{
 struct _finddata_t hi ;
			   long h ;
				int Ok ;
			   char   file[256], fname[100] ;
        static char * findtyp[] = {"\\*_*.jpg",		// 0: jpg  specifiable file types
								   "\\*_*.bmp",		// 1  bmp
								   "\\*_*.ini",		// 2  ini
								   "\\*_*.dat",		// 3  dat   // DATs won't be called for if not needed
								   "\\*_*.trk"} ;	// 4  trk

			 Ok = 0 ;					// presume none found
			 if (p[strlen(p) - 1] != '\\') strcat(p, "\\") ; // ensure backslash

			 strcpy(file, p) ;			// form search target
			 strcat(file, findtyp[t]) ;	// form search target 

			 if ((h = _findfirst(file, &hi)) != -1L)	// seek first
			 {
				 Ok = 1 ;						// have found at least one file of the specified type

				 if (!(hi.attrib & _A_SUBDIR) && !(hi.attrib & _A_HIDDEN))  // skip subdirs and hidden files
				 {
					 strcpy(fname, _strlwr(hi.name)) ;  // get the filename string in lower case
					 InspectFile(hDlg, p, fname) ;		// check if valid and if it is, record it
				 }

				 while(!_findnext(h, &hi))		// any more?
				 {
					 if (!(hi.attrib & _A_SUBDIR) && !(hi.attrib & _A_HIDDEN)) // skip subdirs and hidden files
					 {
						strcpy(fname, _strlwr(hi.name)) ;	// get the filename string in lower case
						InspectFile(hDlg, p, fname) ;		// check if valid and if it is, record it
					 }
				 }
			 _findclose(h) ;
			 }
			 return Ok ; // return 1 on finds, 0 on no finds
}	// MaybeHere()

//************************************
//		 FindFolders()
//
// Find all folders on specified drive.
//
// Can include mapped network drives.
//
// Find Archives on the specified drive.
//
// Calls InspectDirs() to identify
// potential sources of valid files
//  
//************************************
int FindFolders(HWND hDlg, char inputpath[])
{
 static struct _finddata_t  fi ;
 static               long   g ;
 static                int   i, j, k, t, newdepth, dpth, dirfound, typ, ABRlen ;
 static               char * p, * ptr, searchpath[256], pth[256] ;
 static				  char  szABR[] = "Bud Archive" ;
 static				  char szABR1[] = "All Bud Results" ;

// initialise:

	   ABRlen = strlen(szABR) ;
		 dpth = GetDepth(inputpath) ;	// get the depth of the incoming path 
iDirsat[dpth] = 0 ;						// no subdirs at this depth yet found

			// create a buffer for the incoming path.
			if ((p = szDirpath[dpth][iDirsat[dpth]]) != NULL) GlobalFree(p) ;
			p = (char *)GlobalAlloc(GPTR, (strlen(inputpath) + 2) * sizeof( char )) ;
			// get the incoming path into this buffer
			strcpy(p, inputpath) ;
			// get the pointer to it into the list of paths at this depth
			// then increment the number found at this depth
			szDirpath[dpth][iDirsat[dpth]++] = p ;
			// increment the total count of subdirs found
			totaldirs++ ;

dirfound = 1 ; // force a seek for subdirs in the subdirs at this depth

while(dirfound)
{
	dirfound = 0 ; // but presume none will be found

// loop through dirs at current depth
 for ( j = 0 ; j < iDirsat[dpth] ; j++ )
 {
	strcpy( searchpath, szDirpath[dpth][j]) ;	// prepare the search path
	strcat( searchpath, "\\*.*") ; // append backslash and asterisks to denote a general wild card

// look for subdirs on searchpath, which is now the current path

 if ((g = _findfirst(searchpath, &fi)) != -1L) // this is the first one sought
 {
	 if (
		 (fi.attrib & _A_SUBDIR) &&
		!(fi.attrib & _A_SYSTEM) &&
		!(fi.attrib & _A_HIDDEN) 
		) // is a non-hidden, non-system subdir
	 {
		 if (strcmp(fi.name, ".") && strcmp(fi.name, "..")) // exclude (.) and (..)
		 {
			// flag that a subdir has been found.
			 dirfound = 1 ; // sub dir found, allow another pass at its depth
			// form the full path to the new subdir
			 GetNewPath(searchpath, fi.name, pth) ;
			// get the NEW subdir's depth
			 newdepth = GetDepth(pth) ;
			// using the so-far-found number as zero-based index
			// make room for and record the new full path
			//(first free any memory already in use here) 
			 if ((p = szDirpath[newdepth][iDirsat[newdepth]]) != NULL) GlobalFree(p) ;
			 p = (char *)GlobalAlloc(GPTR, (strlen(pth) + 2) * sizeof(char)) ;
			 strcpy(p, pth) ;
			// add the subdir string to the list of subdirs at this depth
			 szDirpath[newdepth][k = iDirsat[newdepth]] = p ;
			 // if this path name contains "Bud Archive...", or "All Bud Results...",
			 // it is part of an archive. If it is unknown, record it,
			 // and place it in the archive tree.
			 if ((ptr = strstr(p, szABR)) != NULL || (ptr = strstr(p, szABR1)) != NULL)
			 {
				 int i, n, ok ;
				 char c, str[256] ;
				// back up to find the preceding backslash 
				 n = ptr - p ;
				 while (*(p + n) != '\\' && (n >= 0)) n-- ;
				 ptr = p + n ;
				// parse from beginning to and include backslash preceding +szABR_ or +szABR1+
				 for (i = 0, n = ptr - p ; i < n ; i++) *(str + i) = *(p + i) ;
				// append backslash and move on
				 *(str + i++) = '\\' ;
				// parse to and include backslash following +szABR+ or +szABR1+,
				// or to the end if no backslash
				while ((c = *(p + i)) != '\\' && c != '\0') *(str + i++) = c ; 
				*(str + i) = '\0' ; // zero terminate
				// do we know this archive?
				 for (i = ok = 0, n = A.iArcs ; i < n ; i++)
				 {
					 if (!strcmp(A.szKnownArc[i], str))
					 { ok = 1 ; break ;} // ok, is known
				 }
				 if (!ok) // not known
				 {
					 if (( p = (char *)GlobalAlloc(GPTR,(strlen(str)+2) * sizeof(char))) != (char *)NULL)
					 {
					 strcpy(p, str) ;

					 A.szKnownArc[A.iArcs++] = p ;
							   PutInTree(hWndTreeArc, 
										 TVI_ROOT,			// place in Tree View ROOT
										 TVI_ROOT,			// place in Tree View ROOT
										 p,					// the Archive string
										 tvArc,				// use Archive icon
										 0) ;				// not needed
					 }
					 else // can't allocate the mem. Tree Insertion skipped.
						 MessageBox(NULL, "No memory available. Skipping.",
										  "Make Room for Archive string", MB_OK) ; 
				 }
			 }

			 // list the directory by its content type.  That is, if
			 // it contains one file of a possibly-valid type, note it
			 // as a potential source of valid files of that type

			 for (t = 0 ; t <= 4 ; t++)
			 {
			 if (t == 3 && !useDATs) continue ;
			 InspectDirs(t, newdepth, k) ;
			 }

			 // then increment the number of subdirs found at this depth 
			 iDirsat[newdepth]++ ;
			 totaldirs++ ;
			 SendMessage(hWndPB2, PBM_STEPIT, 0, 0) ;
		 }
	}
 } // if ((g = _findfirst(searchpath, &fi)) != -1L)
 else // nothing found (unlikely!)
 return -1 ;

// find any remaining subdirs in the current subdir at this depth
 while (!_findnext(g, &fi))
 {
	 if (
		 (fi.attrib & _A_SUBDIR) &&
		!(fi.attrib & _A_SYSTEM) &&
		!(fi.attrib & _A_HIDDEN)
		) // is a non-hidden, non-system, subdir
	 {
		 if (strcmp(fi.name, ".") && strcmp(fi.name, "..")) // exclude (.) and (..)
			{
			 dirfound = 1 ; // sub dir found, allow another pass at its depth

			 GetNewPath(searchpath, fi.name, pth) ;
			 newdepth = GetDepth(pth) ;
			 if ((p = szDirpath[newdepth][iDirsat[newdepth]]) != NULL) GlobalFree(p) ;
			 p = (char *)GlobalAlloc(GPTR, (strlen(pth) + 2) * sizeof(char)) ;
			 strcpy(p, pth) ;
			 szDirpath[newdepth][k = iDirsat[newdepth]] = p ; // retain number of dirs
			 // if this path name contains "Bud Archive...", or "All Bud Results...",
			 // it is part of an archive. If it is unknown, record it,
			 // and place it in the archive tree.
			 if ((ptr = strstr(p, szABR)) != NULL || (ptr = strstr(p, szABR1)) != NULL)
			 {
				 int i, n, ok ;
				 char c, str[256] ;

				// back up to find the preceding backslash 
				 n = ptr - p ;
				 while (*(p + n) != '\\' && (n >= 0)) n-- ;
				 ptr = p + n ;
				// parse from start to and include backslash preceding szABR.. or szABR1..,
				 for (i = 0, n = ptr - p ; i < n ; i++) *(str + i) = *(p + i) ;
				// append backslash and move on
				 *(str + i++) = '\\' ;
				// parse to and include backslash following szABR.. or szABR1..,
				// or to the end if no backslash
				 while ((c = *(p + i)) != '\\' && c != '\0') *(str + i++) = c ; 
				 *(str + i) = '\0' ; // zero terminate
				 // do we know this archive?
				 for (i = ok = 0, n = A.iArcs ; i < n ; i++)
				 {
					 if (!strcmp(A.szKnownArc[i], str))
					 { ok = 1 ; break ;}	// ok, is known
				 }
				 if (!ok)	// not known
				 {
					if ((p = (char *)GlobalAlloc(GPTR,(strlen(str)+2) * sizeof(char))) != (char *)NULL)
					{
					strcpy(p, str) ;
					A.szKnownArc[A.iArcs++] = p ;

							   PutInTree(hWndTreeArc, 
										 TVI_ROOT,			// place in Tree View ROOT
										 TVI_ROOT,			// place in Tree View ROOT
										 p,					// the Archive string
										 tvArc,				// use Archive icon
										 0) ;				// not needed
					}
					else
						MessageBox(NULL, "No memory available. Skipping.",
										 "Make Room for Archive string", MB_OK) ; 
				 }
			 }

			 // list the directory by its content type.  That is, if
			 // it contains one file of a possibly-valid type, note
			 // it as a potential source of valid files of that type

			 for (t = 0 ; t <= 4 ; t++)
			 {
			 if (t == 3 && !useDATs) continue ;
			 InspectDirs(t, newdepth, k) ;
			 }

			 iDirsat[newdepth]++ ;
			 totaldirs++ ;
			 SendMessage(hWndPB2, PBM_STEPIT, 0, 0) ;
			}
	 }
 } // while (!_findnext(g, &fi))

 // emerge here when no more subdirs are found in the current subdir,
 // but with zero or more subdir paths and the latest depth.

 } // for ( j .... search the next subdir at the current depth for subdirs
	
	// when all dirs at the current depth explored for sub dirs...
	 _findclose( g ) ; // close the search at this depth

	dpth = newdepth ;     // go explore the next depth for subdirs.
	deepest = (dpth > deepest) ? dpth : deepest ; // greatest depth reached so far

// However, if no new subdir found during
// the above pass at the current depth,
// stop the whole thing.

} // while(dirfound)
	// if one or more subdirs have been found
	// return the number found
    if (totaldirs) return totaldirs ;
	// otherwise, return the "none found" signal
	return -1 ;

} // FindFolders()

FindArchives()
{
	;
}

// ********************************
// Create a preview (inset) window
// ********************************
HWND PvwPopup
(
HWND hWnd,		// parent
 int x, int y,	// TLC origin in parent
 int w, int h	// width and height
)
{
	HWND hW ;

	hW = CreateWindow(
        "PreviewClass",
        "",
        WS_CHILD, // better without a border
        x, y,
        w, h,
        hWnd, // parent                    
        NULL,
        hInst,
        NULL
    ) ;

	return hW;
}

// ****************************************************
// Get a preview (inset) centred in a destination frame
// ****************************************************
int AdjPVwnd(HWND hWnd, int action)
{
				BITMAP b ;
				 POINT pt ;
	              RECT rc;
			    static stdx, stdy, stdwid, stdhyt ;
			    static usex, usey, usewid, usehyt, mw, mh, iw, ih ;
				static ousex, ousey, ousewid, ousehyt ;
				  char st[100] ;
				  char  w[ 20] ;
				  char  h[ 20] ;

		// destination frame rectangle
			GetWindowRect(GetDlgItem(hWnd, IDC_S_FRAME), &rc) ;

		// express the Frame's window rectangle's 
		// TLC in parent-window client terms
			pt.x = rc.left ;
			pt.y = rc.top ;
			ScreenToClient(hWnd, &pt) ;

		// we want a 5 pixel minimum passe partout
			  usex = stdx = pt.x + 5 ;						// TLC x with least left and right margins
			  usey = stdy = pt.y + 5 ;						// TLC y with least top and bottom margins
			usewid = stdwid = rc.right - rc.left - 10 ;		// greatest inset width
			usehyt = stdhyt = rc.bottom - rc.top - 10 ;		// greatest inset height

		// client-relative mid point of inset
				mw = stdx + stdwid / 2  ;
				mh = stdy + stdhyt / 2  ;

			if (hWnd == hDlgGrabSetUp)
			{
				GetObject(hGrab, sizeof(BITMAP), &b) ;
				wGrb = b.bmWidth ;
				hGrb = b.bmHeight ;
			}
			else

			{
		if (action)
		{
			// adjust inset to the aspect ratio of the image
				GetObject(hPreview, sizeof(BITMAP), &b) ;
				iw = b.bmWidth ; ih = b.bmHeight ;
		}
		else
		{
				GetObject(hDefault, sizeof(BITMAP), &b) ;
				iw = b.bmWidth ; ih = b.bmHeight ;
		}
			}
				_itoa(iw, w, 10) ;
				_itoa(ih, h, 10) ;
				strcpy(st, w) ; strcat(st, " x ") ; strcat(st, h) ;

				if (iw >= ih) 
				{
			// image width is the same as or larger than image height
			// match width to frame, and adjust height
					  usex = stdx ;
					usewid = stdwid ;
					usehyt = MulDiv(stdwid, ih, iw) ;
				}
				else
				{
			// image width is less than image height
			// match height to frame, and adjust width
					  usey = stdy ;
					usehyt = stdhyt ;
					usewid = MulDiv(stdhyt, iw, ih) ;
				}

			// now ensure that the inset
			// does not spill from its frame
				while ( usewid > stdwid || usehyt > stdhyt )
				{
					usewid-- ;
					usehyt = MulDiv(usewid, ih, iw) ;
				}

				while ( usewid < stdwid && usehyt < stdhyt )
				{
					usewid++ ;
					usehyt = MulDiv(usewid, ih, iw) ;
				}
					  usex = mw - usewid / 2  ;
					  usey = mh - usehyt / 2  ;

		if (hWnd == hDlgGrabSetUp) // we're grabbing
		{
			
			// destroy any existing grab 
			if (hWndGrb) DestroyWindow(hWndGrb) ;

			// create a new pop up window
			if ((hWndGrb = PvwPopup(hWnd, usex, usey, usewid, usehyt)) != (HWND)NULL)
			{
				BOOL B ;
					ShowWindow(hWndGrb, SW_SHOW) ;
					// assume dimensions have changed
					B = TRUE ;
					// but erase background only if dimensions have actually changed
				if (ousex == usex && ousey == usey && ousewid == usewid && ousehyt == usehyt)
					B = FALSE ;

				ivrc(hWndGrb, NULL, TRUE) ;
				  UpdateWindow(hWndGrb) ;
			}
			else
				return 0 ;
		}
		else	// we're doing previews in the Archivist
		{
			// destroy any existing preview
			if (hWndPvw) DestroyWindow(hWndPvw) ;

			// create a new pop up window
			if ((hWndPvw = PvwPopup(hWnd, usex, usey, usewid, usehyt)) != (HWND)NULL)
			{
				BOOL B ;
					ShowWindow(hWndPvw, SW_SHOW) ;
					// assume dimensions have changed
					B = TRUE ;
					// but erase background only if dimensions have actually changed
				if (ousex == usex && ousey == usey && ousewid == usewid && ousehyt == usehyt)
					B = FALSE ;

				ivrc(hWndPvw, NULL, B) ;
				  UpdateWindow(hWndPvw) ;

				// display the image dimensions 
				SetWindowText(GetDlgItem(hArcDlg, IDC_S_IMGSIZE), st) ;
			}
			else
				return 0 ;
		}
		ousex = usex ; ousey = usey ; ousewid = usewid ; ousehyt = usehyt ;
		return 1 ;
}


void ResetScan( void )
{
	int i ;

	// clear the "available prefix" combo
			   if (hDlgSource != NULL)
			   ClearCombo(hDlgSource, IDC_CB_PFX) ;

	// clear the trees
			   //TreeView_DeleteAllItems(hWndTree) ;
			   TreeView_DeleteAllItems(hWndTreeSer) ;			   
			   TreeView_DeleteAllItems(hWndTreeExp) ;
			   TreeView_DeleteAllItems(hWndTreeArc) ;

	// clear the tree struct
		memset( &T, 0, sizeof(struct tagTrees) ) ;

	for (i = 0 ; i < deepest ; iDirsat[i++] = 0) ;

		 deepest = 0 ;
		 iSuites = 0 ;
		iImgDirs = 0 ;
		iIniDirs = 0 ;
		iDatDirs = 0 ;
		iTrkDirs = 0 ;
		  budref = 0L ;

	for (i = 0 ; i < MAXARCS ; i++)
	   {
		   if (A.szKnownArc[i] != NULL)
			   GlobalFree(A.szKnownArc[i]) ;
	   }

	for (i = 0 ; i < MAXTAIL ; i++)
	   {
		   if (A.szKnowntail[i] != NULL)
			   GlobalFree(A.szKnowntail[i]) ;

		   if (A.Suitepertail[i] != (LPSUITE)NULL)
			   GlobalFree(A.Suitepertail[i]) ;
	   }

	for (i = 0 ; i < MAXPFXS ; i++)
	{
		   openpfx[i] = 0 ;

		if (A.szKnownpfx[i] != NULL)
		GlobalFree(A.szKnownpfx[i]) ;
	}

	for (i = 0 ; i < MAXPTHS ; i++)
	{
		if (A.szKnownpth[i] != NULL)
		GlobalFree( A.szKnownpth[i] ) ;
	}

	for (i = 0 ; i < MAXINST ; i++)
	{
		iImgDirIndex[i] = 0 ;
		iIniDirIndex[i] = 0 ;
		iDatDirIndex[i] = 0 ;
		iTrkDirIndex[i] = 0 ;

		iImgDirDepth[i] = 0 ;
		iIniDirDepth[i] = 0 ;
		iDatDirDepth[i] = 0 ;
		iTrkDirDepth[i] = 0 ;

		if (A.szKnownimg[i] != NULL)
		GlobalFree(A.szKnownimg[i]) ;

		if (A.szImgdate[i] != NULL)
		GlobalFree(A.szImgdate[i]) ;

		if (A.szKnownini[i] != NULL)
		GlobalFree(A.szKnownini[i]) ;

		if (A.szKnowntrk[i] != NULL)
		GlobalFree(A.szKnowntrk[i]) ;

		if (A.szKnowndat[i] != NULL)
		GlobalFree(A.szKnowndat[i]) ;
	}

	// clear the Archive struct
		memset(&A, 0, sizeof(struct tagARCHIVE)) ;
}

// for treeview hit-testing.
// works on a timer. 
HWND PickTree(LPPOINT pt)
{
			 HWND hWndPoint ;
			 HWND hWndChild ;

			GetCursorPos(pt) ;
			hWndPoint = WindowFromPoint(*pt) ;
		if (hWndPoint != (HWND)NULL)
		{
			ScreenToClient(hWndPoint, pt) ;
			while (TRUE)
			{
				hWndChild = ChildWindowFromPoint(hWndPoint, *pt) ;
				if (hWndChild && hWndChild != hWndPoint)
					hWndPoint = hWndChild ;
					else
					break;
			}
		}
		return hWndPoint ;
}

/******************************************************************
	Archivist Dialogue
*******************************************************************/

BOOL CALLBACK ArchivistDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
    LPDRAWITEMSTRUCT lpdis ;
			  static numdrives ;
				 int i ;
				 int flag = 0 ;
			  static stdx, stdy, stdwid, stdhyt, wid, hyt ;
			  static usex, usey, usewid, usehyt, mw, mh, iw, ih ;
			  static char iniPth[256], iniName[256] ;
		      //char szInstinfo[200] ;

	switch(msg)
	{

	case WM_INITDIALOG: // is non-modal dialog box - initialised only once (when first used)

			SetDlgItemText(hDlg, IDC_E_SEARCHZONE, szSearchDir) ;	// fill the tell-tale from bud.ini
			CheckDlgButton(hDlg, IDC_C_USEDATS, BST_UNCHECKED) ;	// default will be, don't use

			hWndPB2 = GetDlgItem(hDlg, IDC_SCANPROGRESS) ;
			hWndPB3 = GetDlgItem(hDlg, IDC_SCANPROGRESS2) ;
			SendMessage(hWndPB2, PBM_SETRANGE, 0, MAKELPARAM(0, 5000)) ;			
			SendMessage(hWndPB2, PBM_SETPOS, (WPARAM) 0, 0) ;
			SendMessage(hWndPB3, PBM_SETRANGE, 0, MAKELPARAM(0, 5000)) ;			
			SendMessage(hWndPB3, PBM_SETPOS, (WPARAM) 0, 0) ;

			showpreview = searched ;


			AdjPVwnd(hDlg, showpreview) ;

		return TRUE ;

	case WM_DRAWITEM:
		lpdis = (LPDRAWITEMSTRUCT)lParam ;

	if (lpdis->itemAction == ODA_SELECT)
		{
		  HDC hmemDC, hdc ;
		  HBITMAP oBm ;
		  RECT r ;
		  UINT wd, ht, Wd, Ht, WD, HT ;

			   r.right  = lpdis->rcItem.right ;
			   r.left   = lpdis->rcItem.left ;
			   r.top    = lpdis->rcItem.top ;
			   r.bottom = lpdis->rcItem.bottom ;

			   Wd = r.right - r.left ;
			   Ht = r.bottom - r.top ;

			   hdc = lpdis->hDC ;
			hmemDC = CreateCompatibleDC(hdc) ;

			for ( i = 0 ; i < 2 ; i++)
			{
				if (!i)
				{
			   oBm = SelectObject(hmemDC, hDefault) ;
			    wd = Wd ; WD = 70 ;
			    ht = Ht ; HT = 80 ;
				goto jump ;
				}
				else
				{
			   oBm = SelectObject(hmemDC, hPreview) ;
			    wd = WD = wPrview ;
			    ht = HT = hPrview ;
				}

				while ( wd > Wd || ht > Ht )
				{
					wd-- ;
					ht = MulDiv(wd, HT, WD) ;
				}

				while ( wd < Wd && ht < Ht )
				{
					wd++ ;
					ht = MulDiv(wd, HT, WD) ;
				}

jump:	SetStretchBltMode(hdc, COLORONCOLOR) ;
			
		StretchBlt( hdc,			// Destination DC
					0,				// x Top Left Corner destination
					0,				// y TLC destination
					wd, ht,			// pixel width & height in destination
					hmemDC,			// Source DC
					0, 0,			// x,y TLC source
					WD, HT,			// width & height in source
					SRCCOPY );		// raster operation (copy)
			}
		SelectObject(hmemDC, oBm) ;
		DeleteDC( hmemDC ) ;				  // clear up
		DeleteDC( hdc ) ;
		}
		return TRUE ;
		break ;

	case WM_NOTIFY:
		{
			static char * typ[] = {"No Selection", "Prefix",       "Image",    "INI file",    "TRK file",
				                       "DAT file",   "Path", "Path to IMG", "Path to INI", "Path to TRK",
								   "Path to DAT"} ;
			char    cdir[MAX_PATH] ;
			char     txt[256] ;
			char    txt1[256] ;
			char    buff[256] ;
			char  imgtxt[256] ;
			char  pthtxt[256] ;
	 static char oimgtxt[256] ;
	 static char opthtxt[256] ;
			char  dirtxt[256] ;
			UINT ID, TYP, itemdata[3] ;
			UINT ID1, TYP1 ;
			UINT n, PFD, INIPFD, images ;
		 LPNMHDR hdr ;

		//get Windows directory
				GetWindowsDirectory(cdir, MAX_PATH) ;
				if ((cdir[strlen(cdir) - 1]) != '\\') strcat(cdir, "\\") ;

		 hdr = (LPNMHDR)lParam ;

		 if (hdr->hwndFrom == hWndTreeExp)
		 {
		 switch(hdr->code)
		 {
		 case TVN_SELCHANGED:  // respond to change of tree view item selection

			 htvSel = TreeView_GetSelection(hWndTreeExp) ; // get HANDLE of selected item

			 tvItm.mask = TVIF_TEXT | TVIF_PARAM ;		// specify items wanted
			 tvItm.hItem = htvSel ;						// give the selection's handle
			 tvItm.pszText = txt ;						// text buffer
			 tvItm.cchTextMax = 256 ;					// length of text buffer

			 TreeView_GetItem(hWndTreeExp, &tvItm) ;	// go get the item (fills the tvItm struct)
			    TYP = GetItemData(hWndTreeExp, htvSel, itemdata) ;		// get the items data
			     ID = itemdata[1] ;

			 SetDlgItemText(hDlg, IDC_E_TELLTALE2, typ[TYP]) ;			// display the type
			 SetDlgItemInt( hDlg, IDC_E_TELLTALE1, (UINT)ID , FALSE) ;	// display the ID

			 // on selection of a prefix (must happen before any other selection can be made)
			 if (TYP == PFX)
			 {
				 static HTREEITEM hti, ohti ;
				 int n ;
				 UINT id, typ ;

				// show the prefix
				SetDlgItemText(hDlg, IDC_E_PREFIX, txt) ;
				// expand this prefix in the Suites and Sets tree
				if ((hti = SearchTree(hWndTreeSer, 0, txt, &id, &typ))!= (HTREEITEM)NULL) ;
				TreeView_SelectItem(hWndTreeSer, hti) ;

				IsInst = 0 ;
				CurrentPfxID = ID ;
				//EnableWindow(GetDlgItem(hDlg, IDC_B_SET2BW), TRUE);

				// get and display the number of images or auxiliaries known to this prefix
				if ((n = images = A.iNumImgperpfx[ID]) > 0)
				{ // if images, use number of images
					SetWindowText(GetDlgItem(hDlg, IDC_S_INSTTYP), "Images:") ;
					goto useit ;
				}
				if ((n = A.iNumIniperpfx[ID]) > 0)
				{ // if no images, use number of INIs
					SetWindowText(GetDlgItem(hDlg, IDC_S_INSTTYP), "INIs:") ;
					goto useit ;
				}
				if ((n = A.iNumDatperpfx[ID]) > 0)
				{ // if no images or INIs, use number of DATs
					SetWindowText(GetDlgItem(hDlg, IDC_S_INSTTYP), "DATs:") ;
					goto useit ;
				}
				// if none of the above, say none
					SetWindowText(GetDlgItem(hDlg, IDC_S_INSTTYP), "None:") ;
					 n = 0 ;

useit: ;
				SetDlgItemInt(hDlg, IDC_E_NUMINSTS, n, FALSE) ;

					 // clear all else to empty
				SetDlgItemText(hDlg, IDC_E_INSTIDENTITY, "") ;
				SetDlgItemText(hDlg, IDC_E_INSTEPOCH,    "") ;
				SetDlgItemText(hDlg, IDC_E_EARLY,        "") ;
				SetDlgItemText(hDlg, IDC_E_LATE,         "") ;
				SetWindowText(GetDlgItem(hDlg, IDC_B_SEL2BWFROM), "use") ;
				SetWindowText(GetDlgItem(hDlg, IDC_S_TELLTALE),    ""    ) ;
				SetWindowText(GetDlgItem(hDlg, IDC_S_IMGSIZE),     ""    ) ;
			     EnableWindow(GetDlgItem(hDlg, IDC_B_SEL2BW),       FALSE) ;
				 EnableWindow(GetDlgItem(hDlg, IDC_B_SEL2BWFROM),   FALSE) ;
				 EnableWindow(GetDlgItem(hDlg, IDC_B_FULL_INI),     FALSE) ;
							  ClearCombo(hDlg, IDC_CB_BUDINFO) ;
							  showpreview = 0 ;

				if (!images)	// if no images
				{
					// disallow selection into workshop
					EnableWindow(GetDlgItem(hDlg,IDC_B_SEL2BW),     FALSE) ;
					EnableWindow(GetDlgItem(hDlg,IDC_B_SEL2BWFROM), FALSE) ;
					// Open the  "No image" image in preview
					strcpy(szNoImageFile, cdir) ;
					strcat(szNoImageFile, "noimage.jpg") ;
					OpenPreview(hDlg, szNoImageFile) ;
					showpreview = 1 ;
				}
				AdjPVwnd(hDlg, 1) ;
			 }
			 /*++			
			 if (TYP == IMG){;}
			 if (TYP == INI){;}
			 if (TYP == DAT){;}
			 if (TYP == TRK){:}
			 --*/

			// on selection of any path type, 
			 if (TYP == IMGPTH || TYP == INIPTH || TYP == DATPTH || TYP == TRKPTH)
			 {
				// a path-selection has the item on that
				// path as its parent in the tree.
				// so get the parent item, and determine its type.
				// to do this, first get the handle of the parent item
				 htvDaddy = TreeView_GetParent(hWndTreeExp, htvSel) ;

			 // specify the wanted details
			 tvItm1.mask = TVIF_TEXT | TVIF_PARAM ;		// want the text and the user number (composite ID)
			 tvItm1.hItem = htvDaddy ;					// give the parent's handle
			 tvItm1.pszText = txt1 ;					// text buffer
			 tvItm1.cchTextMax = 256 ;					// length of text buffer

			 TreeView_GetItem(hWndTreeExp, &tvItm1) ;		// go get the parent item (fills the tvItm1 struct)

			  TYP1 = GetItemData(hWndTreeSer, htvDaddy, itemdata) ;		// get the items data
			   ID1 = itemdata[1] ;

			// if the parent item on the selected path
			// is an image, display that image in preview.
			  if (TYP1 == IMG)
			  {

				PFD = A.iImgPfxID[ID1] ;	// get the prefix ID for this instance
				n = A.iNuminiperimg[ID1] ;	// get number of INIs associated with this instance image
				strcpy(pthtxt, txt) ;		// txt  should hold the path - copy for local use
				strcpy(imgtxt, txt1) ;		// txt1 should hold the image file name - copy for local use
				// if old image and path texts are empty,
				// they have not yet been used. Fill them
				// with the incoming texts.
				if (oimgtxt[0] == '\0') strcpy(oimgtxt, imgtxt) ;
				if (opthtxt[0] == '\0') strcpy(opthtxt, pthtxt) ;
				// if old and new file names or paths differ,
				// or if there are no INIs for this instance,
				// remove currently displayed bud info, if any,
				// clear the "(load) using" button text, disable
				// this button, and disable the 'Full INI' button.
				if ((strcmp(imgtxt, oimgtxt)) || (strcmp(pthtxt, opthtxt) || !n))
				{
					ClearCombo(hDlg, IDC_CB_BUDINFO) ;
					 EnableWindow(GetDlgItem(hDlg, IDC_B_FULL_INI),      FALSE) ;
					SetWindowText(GetDlgItem(hDlg, IDC_B_SEL2BWFROM),   "use ") ;
					 EnableWindow(GetDlgItem(hDlg, IDC_B_SEL2BWFROM),    FALSE) ;
					SetWindowText(GetDlgItem(hDlg, IDC_S_TELLTALE), ""        ) ;
				}
				strcpy(oimgtxt, imgtxt ) ;							// for next check
				strcpy(opthtxt, pthtxt) ;							// for next check
				SetDlgItemText(hDlg, IDC_E_INSTIDENTITY, imgtxt) ;	// display the instance name over the preview
				strcpy(dirtxt, "Image Dir: ") ;						// display the image path
				strcat(dirtxt, pthtxt) ;
				SetDlgItemText(hDlg, IDC_E_INSTEPOCH, A.szImgdate[ID1]) ;// display the epoch over the preview
				n = A.iNumImgperpfx[PFD] ;				// get and display the earliest and latest instance epochs
				SetDlgItemText(hDlg, IDC_E_EARLY, A.szImgdate[A.Imgperpfx[PFD][0]]) ;
				SetDlgItemText(hDlg, IDC_E_LATE,  A.szImgdate[A.Imgperpfx[PFD][n - 1]]) ;
				// concatenate path and image file name
				strcpy(szMRUpvu, pthtxt) ; strcat(szMRUpvu, imgtxt) ;
				OpenPreview(hDlg, szMRUpvu) ;	// Open the preview image
				showpreview = 1 ;
				AdjPVwnd(hDlg, showpreview) ;
				EnableWindow(GetDlgItem(hDlg, IDC_B_SEL2BW), TRUE) ;	// Enable the "Open in BW " (Load) button
				goto get_out ;
			  }

			  if (TYP1 == INI)	// we will want to open the INI on this path
			  {					// - possibly in its own Tree View?
				 // txt  should hold the path,
				 // txt1 should hold the INI filename.extension
				  char tail[100] ;
				  char ininame[256] ;
				  char str[100] ;
				   int c, j, Ok, tailID ;
				  HWND btt, bfrm, b2bw ;
						 btt = GetDlgItem(hDlg, IDC_S_TELLTALE  ) ;
						b2bw = GetDlgItem(hDlg, IDC_B_SEL2BW    ) ;
						bfrm = GetDlgItem(hDlg, IDC_B_SEL2BWFROM) ;
					
				// this is for the ini read-out, whether or not an image is in preview				
					INIPFD = A.iIniPfxID[ID1] ;			// get the prefix ID corresponding to the INI
					strcpy(tail, getlastcomp(txt)) ;	// grab the tail

					for (j = Ok = 0 ; j < A.iTails ; j++) // check against known tails
					{
						if (!strcmp(A.szKnowntail[j], tail))
						{
								SetWindowText(btt, tail) ;	// show INI suite text above preview panel
								tailID = j ; Ok = 1 ;		// we have the tail ID
								break ;
						}
					}
						if(!Ok)	// we don't know this tail at all
							SetWindowText(btt, "No Suite") ;

					// now check if we can load from the tree: we can do so only if an image is in preview,
					// and the filenames less extensions match (if we have a match of both prefix and epoch
					// for the INI and the IMG now in preview)
					if (IsWindowEnabled(b2bw)) // ( means an image is in preview and so imgtxt should exist)
					{
						if (!strcmp(_strlwr(DropExt(txt1)), _strlwr(DropExt(imgtxt))))
						{
									  int i, Ok1 ;
								  LPSUITE ps ;
								// ok, things match so far but
								// we can load only if the prefix also knows the suite
									for (i = Ok1 = 0 ; i < A.iNumsuiperpfx[INIPFD] ; i++) // check known suites of prefix
									{
									ps  = A.pSuiteperpfx[INIPFD][i] ;   // get a suite of the prefix
									if (!strcmp(ps->desc, tail))		// compare its description with incoming tail
										{
										Ok1 = 1 ;						// suite description and tail match
										OldSuite = UseSuite ;
										OldBudPfxID = BudPfxID ;
										UseSuite = i ;					// got it, perhaps use it
										LoadImgbyTree = 1 ;				// this is a load from the tree
										strcpy(str, "use ") ; strcat(str, tail) ;
										strcpy(szCurrentSuite, tail) ;
										SetWindowText(bfrm, str) ; // suite text on 'load from' button
										EnableWindow(bfrm, TRUE) ; // enable button to load this instance from this suite
										goto can_load ;
										}
									}
									if (!Ok1) goto cant_load ;
						}
					}
					else // there is no image in preview
					{
cant_load:					strcpy(str, "use ") ;		// so say so on button 
							SetWindowText(bfrm, str) ;
							LoadImgbyTree = 0 ;			// not loading from tree
							EnableWindow(bfrm, FALSE) ; // disable the "load from' button
					}

		// having perhaps enabled an optional load, return to the read-out from the ini file
				
can_load:		strcpy(ininame, txt ) ;	// path to ini
				strcat(ininame, txt1) ; // concat. ini name with path

				strcpy(iniPth,  txt) ;	// for full INI display
				strcpy(iniName, txt1) ;	// for full INI display

				// unconditionally clear the Bud Info display,
				// and enable the full INI button
				ClearCombo(hDlg, IDC_CB_BUDINFO) ;
				EnableWindow(GetDlgItem(hDlg, IDC_B_FULL_INI), TRUE) ;

				// fill the Bud Info combo from the INI

				c = 0 ;	// combo index

// Projective **********
				gpps("Projective Lambdas & MRDs", "Pr_Diam", "None",
					  buff, (DWORD)256, ininame) ;					// projective on diameters
				PutCBEdBox(hDlg, IDC_CB_BUDINFO, buff) ;			// index 0 item to combo edit box
				InsInCombo(hDlg, IDC_CB_BUDINFO, buff, c++) ;		// same item as 0'th combo string
				gpps("Projective Lambdas & MRDs", "Pr_LRad", "None",
					  buff, (DWORD)256, ininame) ;					// projective on left radii
				InsInCombo(hDlg, IDC_CB_BUDINFO, buff, c++) ;		//
				gpps("Projective Lambdas & MRDs", "Pr_RRad", "None",
					  buff, (DWORD)256, ininame) ;					// projective on right radii
				InsInCombo(hDlg, IDC_CB_BUDINFO, buff, c++) ;		//

// Regression **********
				gpps("Regression Lambdas & MRDs", "Rg_Diam", "None",
					  buff, (DWORD)256, ininame) ;					// regression on diameters
				InsInCombo(hDlg, IDC_CB_BUDINFO, buff, c++) ;
				gpps("Regression Lambdas & MRDs", "Rg_LRad", "None",
					  buff, (DWORD)256, ininame) ;					// regression on left radii
				InsInCombo(hDlg, IDC_CB_BUDINFO, buff, c++) ;		//
				gpps("Regression Lambdas & MRDs", "Rg_RRad", "None",
					  buff, (DWORD)256, ininame) ;					// regression on right radii
				InsInCombo(hDlg, IDC_CB_BUDINFO, buff, c++) ;		//
			  } // if (TYP1 == INI)

			  if (TYP1 == TRK)	// we want to show the Track on this path
			  {					// on the preview image
				 // txt  should hold the path,
				 // txt1 should hold the TRK file name
				  char szTrk[256] ;
				  int h ;

				// show the track only if there's an image to match
				 if (images) // is image?
				 {
				  // there's an image
				   strcpy(szTrk, txt) ;
				   strcat(szTrk, txt1) ;

				  if ((h = ReadTrkFile(&tk, szTrk)) != 0) // read in the track information
				  {
					   int i, plot_it, s, x, y, px, py ;
					   int swd, sht ; // source
					   int twd, tht ; // target
					    HDC hdc ;
					   HPEN oP ;
					 BITMAP bm ;
					   RECT rc ;

					// show the track only if an image is showing
					if (hPreview != (HBITMAP)NULL)
					{
					hdc = GetDC(hWndPvw) ;
					 oP = SelectObject(hdc, ltbluePen) ;
				    GetObject(hPreview, sizeof(BITMAP), &bm) ;
					GetWindowRect(hWndPvw, &rc) ;
					swd = bm.bmWidth ;				// source
					sht = bm.bmHeight ;
					twd = rc.right - rc.left ;		// target
					tht = rc.bottom - rc.top ;
					for ( i = 0, plot_it = 0 ; i < h ; i++ )	// left profile
					{
						if ((s = tk.Beplft[i]) >= 0)
						{
							  x = s ; y = h - i ;
							 py = MulDiv(y, tht, sht) ;
							 px = MulDiv(x, twd, swd) ;
							 if (!plot_it)
							 { MoveToEx( hdc, px - 1, py, NULL) ; plot_it = 1 ; }
							 else LineTo( hdc, px, py) ;
						}
					}
					for ( i = 0, plot_it = 0 ; i < h ; i++ )	// right profile
					{
						if ((s = tk.Bepryt[i]) >= 0)
						{
							  x = s ; y = h - i ;
							 py = MulDiv(y, tht, sht) ;
							 px = MulDiv(x, twd, swd) ;
							 if (!plot_it)
							 { MoveToEx( hdc, px, py, NULL) ; plot_it = 1 ; }
							 else LineTo( hdc, px - 1, py) ;
						}
					}
					SelectObject(hdc, oP) ;
					ReleaseDC(hWndPvw, hdc) ;
					}
				  }
				}
				else // there is no image
					MessageBeep(MB_ICONEXCLAMATION) ;
			  }

			  if (TYP1 == DAT)
			  {	
				 // txt  should hold the path,
				 // txt1 should hold the DAT file name
				  MessageBeep(MB_ICONEXCLAMATION) ; // just to test
			  }
			 }

get_out:     break ;

		 default:
			 break ;
		  }	// switch(hdr->code)
		 } // if (hdr->hwndFrom----)


		 if (hdr->hwndFrom == hWndTreeSer)	// series and sets tree
		 {
			 switch(hdr->code)
			 {
			 case TVN_SELCHANGED:  // respond to change of tree view item selection
			 htvSel = TreeView_GetSelection(hWndTreeSer) ; // get HANDLE of selected item

			 tvItm.mask = TVIF_TEXT | TVIF_PARAM ;		// specify items wanted
			 tvItm.hItem = htvSel ;						// give the selection's handle
			 tvItm.pszText = txt ;						// text buffer
			 tvItm.cchTextMax = 256 ;					// length of text buffer

			 TreeView_GetItem(hWndTreeSer, &tvItm) ;		// go get the item (fills the tvItm struct)

			  TYP = GetItemData(hWndTreeSer, htvSel, itemdata) ;		// get the item's data
			   ID = itemdata[1] ;

			  if (TYP == PFX)	// if we have selected a prefix
			  {
				 static HTREEITEM hti, ohti ;
				 UINT id, typ ;

				SetDlgItemText(hDlg, IDC_E_PREFIX, txt) ;			// display prefix
				if ((hti = SearchTree(hWndTreeExp, 0, txt, &id, &typ)) != (HTREEITEM)NULL) ;	// find in other tree
				TreeView_SelectItem(hWndTreeExp, hti) ;				// select/expand this prefix in other tree 
			  }
/*****
			  if (TYP == SUIT)	// if we have selected a suite (then it must exist!)
			  {
				  char st[80] ;
				   HWND btn, btn1 ;
				   btn  = GetDlgItem(hDlg, IDC_B_SEL2BWFROM) ;
				   btn1 = GetDlgItem(hDlg, IDC_B_SEL2BW) ;

				  // txt should hold the suite description
				  // ID should hold the suite ID

					// check if 'Select to Wkshp' btn is on (meaning that we've selected an image)
					LoadImgbyTree = (IsWindowEnabled(btn1) == TRUE) ? 1 : 0 ;

					if (LoadImgbyTree)
					{
						OldSuite = UseSuite ;
						UseSuite = ID ;	// use the suite
						strcpy(st, "use ") ; strcat(st, txt) ; // use it's name
						SetWindowText(btn, st) ;	// set button text to suite name
						EnableWindow( btn, TRUE) ;	// enable it
					}
					else  // no image selected
					{
						strcpy(st, "use ") ;
						SetWindowText(btn, st) ;	// set button text to ^no suite"
						EnableWindow(btn, FALSE) ;	// disable it
					}
			  }
*****/
				 break ;

			 default:
				 break ;
			 }	// switch(hdr->code)
		 } // if (hdr->hwndFrom == hWndTreeSer)

		 if (hdr->hwndFrom == hWndTreeArc)
		 {
			 switch(hdr->code)
			 {
			 case TVN_SELCHANGED:  // respond to change of tree view item selection

			 tvItm.mask = TVIF_TEXT | TVIF_PARAM ;		// specify items wanted
			 tvItm.hItem = htvSel ;						// give the selection's handle
			 tvItm.pszText = txt ;						// text buffer
			 tvItm.cchTextMax = 256 ;					// length of text buffer

			 TreeView_GetItem(hWndTreeSer, &tvItm) ;	// go get the item (fills the tvItm struct)

			 TYP = ID = (UINT)tvItm.lParam ;	// get the composite ID
			 TYP >>= 24 ;				// right-shift top 8 bits to bottom to obtain the type
			  ID &= 0x00FFFFFF ;		// zero the topmost 8 bits of the ID to isolate the ID

				 break ;

			 default:
				 break ;
			 }	// switch(hdr->code)
		 } // if (hdr->hwndFrom == hWndTreeArc)

		}
		break ; // WM_NOTIFY

	case WM_TIMER:
		switch (wParam)
		{
			default:
				break ;
		}
		break ;

	case WM_COMMAND:
 // *************************************************
 // detect notifications via WM_COMMAND from controls
 // *************************************************
	switch(HIWORD(wParam))
	{
		default: break ; // for	switch(HIWORD(wParam))
	} // end of detect notifications

	switch(LOWORD(wParam))
	{
	case IDOK:
		break ;

	case IDCANCEL:
		break ;

	case IDC_C_SET_SEARCHZONE:
		SendMessage(hWndCtrl,WM_COMMAND,IDM_SET_SEARCH,0L) ;				// change the default zone
		break ;


	case IDC_C_STATS:
		showstats = IsDlgButtonChecked(hDlg, IDC_C_STATS) ;
		if (showstats)
			{
			char nstr[50] ;
				if (hDlgStats == (HWND)NULL)
					hDlgStats = CreateDialog(
						hInst,
						MAKEINTRESOURCE(IDD_SEARCH_STATS),
						hWndCtrl,
						SearchStatsDlgProc ) ;

					ShowWindow(hDlgStats, SW_SHOW) ;	// show the search statistics

					SetWindowPos(hDlgStats, HWND_TOP,	// be sure it comes up tops
					         0,0,0,0,
							 SWP_NOSIZE|SWP_NOMOVE) ;

								SetWindowText(GetDlgItem(hDlgStats, IDC_S_ITEMCOUNT), T.szItems ) ;
								_ltoa(budref, nstr, 10) ;
								strcat(nstr, " Bud Files") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_VALIDCOUNT), nstr) ;
								_itoa(iSuites, nstr, 10) ;
								strcat(nstr, " Suites") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_SUITECOUNT), nstr) ;
								_itoa(A.iPfxIDs, nstr, 10) ;
								strcat(nstr, " Prefixes") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_PREFIXES), nstr) ;
								_itoa(A.iGpthIDs, nstr, 10) ;
								strcat(nstr, " Paths") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_PATHCOUNT), nstr) ;
								_itoa(A.iImgIDs, nstr, 10) ;
								strcat(nstr, " Images") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_INSTANCES), nstr) ;
								_itoa(A.iIniIDs, nstr,10) ;
								strcat(nstr, " INIs") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_INIS), nstr) ;
								_itoa(A.iDatIDs, nstr,10) ;
								strcat(nstr, " DATs") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_DATS), nstr) ;
								_itoa(A.iTrkIDs, nstr,10) ;
								strcat(nstr, " TRKs") ;
								SetWindowText(GetDlgItem(hDlgStats, IDC_S_KNOWN_TRKS), nstr) ;
		}
			else
			{
				ShowWindow(hDlgStats, SW_HIDE) ;		// hide the search statistics
			}
			return 0 ;

	case IDC_HIDE_ARCHIVIST:
		SendMessage(hWndColl, WM_COMMAND, IDM_ARCHIVIST, 0L) ;
		break ;

		// there is a bug here somewhere! The incumbent is not being properly recorded.

	case IDC_B_SEL2BW:	// select the INSTANCE currently in preview into the BW.
		UpdatingRecords = IsInst = 1 ;
		if (gotimage) toArchive = 1 ; // archive any instance currently in work
		Select2BW = 1 ;
		SendMessage(hWndCtrl,WM_COMMAND,IDM_OPEN_FILE,0L) ;
		UpdatingRecords = 0 ;
		break ;

	case IDC_B_SEL2BWFROM:	// select the INSTANCE currently in preview into the BW.
		UpdatingRecords = IsInst = 1 ;
		if (gotimage) toArchive = 1 ; // only if an instance is currently in work
		Select2BW = 1 ;
		SendMessage(hWndCtrl,WM_COMMAND,IDM_OPEN_FILE,0L) ;
		UpdatingRecords = 0 ;
		break ;

	case IDC_B_FULL_INI:
	    ShellExecute(hWndCtrl, "open", iniName, NULL, iniPth, SW_SHOWNORMAL) ;
		break ;

	case IDC_B_BATCH: // sequentially load and update all images in a suite
		batching ^= 1 ;  // toggle
			if (batching)
				SetWindowText(GetDlgItem(hArcDlg, IDC_B_BATCH), "Batching") ;
			else
				SetWindowText(GetDlgItem(hArcDlg, IDC_B_BATCH), "Batch") ;

		while (batching)
			SendMessage(hWndCtrl, WM_COMMAND, IDM_NEXT_FILE, 0L) ;

		break ;

	case IDC_C_USEDATS:
		 if (IsDlgButtonChecked(hDlg, IDC_C_USEDATS))
		 {
		// if we have an incumbent,
		// save it before toggling DAT use
			 if (gotimage) SaveAllAway() ; 
			 useDATs = useDATs ? 0 : 1 ;
		 }
		break ;

	case IDC_B_SEARCHSYSTEM:
		{
		  //int i ;
		   UINT j, d, n ;
		   char inputpath[256] ;
		   char   wndtext[256] = "\0" ;
		   char   string1[256] = "The Archivist is finding Folders and Archives on " ;
		   char   string2[256] = "The Archivist is searching for valid " ;
		   char    string[256] ;

		 StartWait() ;
		 SetWindowText(GetDlgItem(hArcDlg, IDC_B_SEARCHSYSTEM), "Find Items") ;
		   searched = 0 ;
		  searching = 1 ;

		  // deal with any incumbent image
		  if (gotimage)
		  {
			  strcpy(szArchFile, szFile) ;
			  SaveAllAway() ;
		  }
			// clear the way
			ResetScan() ;
			// reset progress bar
			SendMessage(hWndPB2, PBM_SETPOS, (WPARAM) 0, 0) ;
			SetWindowText(GetDlgItem(hDlg, IDC_S_DOINGDRIVE), "Searching..") ;
			// build folder list for the
			// search zone
			GetWindowText(hArcDlg, wndtext, 256) ;

			strcpy(inputpath, szSearchDir) ;

				if (FindFolders(hArcDlg, inputpath) == -1L)
				{
					char str[256] ;
					strcpy(str, "No folders found on ") ;
					strcat(str, inputpath) ;
					MessageBox(NULL, str,"System Scan", MB_OK) ;
				}

				// All available archives and folders with possibly
				// valid stuff now found on the selected drives.

	// Archive selection or creation
			{
			char  narc[] = {"No Archive has been found in your Search Directory.\nWould you like to specify another Directory?\nIf you choose not to do so,the Bud Workshop will now Shut Down."} ;
			char narc1[] = "No Archive has been selected.\n The Bud Workshop will Shut Down." ;
			char narc2[] = "No Bud Files were found in your Search Directory.\nWould you like to specify another?\nIf you choose not to do so, the Bud Workshop will Shut Down." ;

				if (A.iArcs == 1) // only one found, use it!
				{
					/*****
					char a[256], b[256], c ;
					 int i, j, len ;
					 strcpy(a, A.szKnownArc[0]) ;
					 len = strlen(a) ;
					 for ( i = 0, j = 0 ; i < len  ; i++)	// copy string from a to b
						{
						c = b[j++] = a[i] ;
						if (c == '\\') { b[j++] = c ; }		// however, if a backslash found in a, immediately insert another in b
						}
							b[j] = '\0' ;					// zero terminate
							***/
					strcpy(szUsingArchive, A.szKnownArc[0]) ;				// we'll use this one
					goto chosen ;
				}

				if (A.iArcs > 1) // more than one Archive exists. choose one.
				{
					int response ;
					response = DialogBox(hInst,
										 MAKEINTRESOURCE(IDD_PICK_ARCHIVE),
										 hArcDlg,
										 PickArcDlgProc) ;

					if (response == IDCANCEL)
					{
						MessageBox(NULL, narc1, "Archive", MB_ICONEXCLAMATION|MB_OK) ;
						SendMessage(hWndCtrl,WM_COMMAND,IDM_EXIT,0L) ;
					}
				}
				if (A.iArcs == 0)		// if none found, supply opportunity to create one, or quit
				{
					int Usersays ;
					// for now, just quit
					Usersays = MessageBox(NULL, narc2, "Archive", MB_ICONEXCLAMATION|MB_YESNO) ;
					if (Usersays == IDYES)
					SendMessage(hWndCtrl, WM_COMMAND, IDM_SET_SEARCH, 0L) ;
					else
					SendMessage(hWndCtrl, WM_COMMAND, IDM_EXIT,0L) ;
				}
			}
				
		// Archive has been chosen: get on with the search

chosen:			strcpy(AllImg, szUsingArchive) ;
				strcat(AllImg, "\\\\") ; // why two backslashes?
				strcat(AllImg, "All IMG" ) ;
					strcpy(AllIni, szUsingArchive) ;
					strcat(AllIni,"\\" ) ;
					strcat(AllIni, "All INI" ) ;
						strcpy(AllDat, szUsingArchive) ;
						strcat(AllDat, "\\" ) ;
						strcat(AllDat, "All DAT" ) ;
							strcpy(AllTrk, szUsingArchive) ;
							strcat(AllTrk, "\\" ) ;
							strcat(AllTrk, "All TRK" ) ;

				// look for files in definite order, images first,
				// to facilitate identification of orphaned files.

		// look for valid IMGs
				strcpy(string, string2) ;				//	"..is searching for valid " 
				strcat(string, "Images in ") ;			//  "<type> on "
				strcat(string, szSearchDir) ;
				SetWindowText(hArcDlg, string) ;

				for (j = 0 ; j < iImgDirs ; j++)
				{
					n = iImgDirIndex[j] ; // there is one possibly-valid image in this folder 
					d = iImgDirDepth[j] ; // at this depth, and there may be others: seek them all out
					MaybeHere(hArcDlg, szDirpath[d][n], 0) ; // jpg
					MaybeHere(hArcDlg, szDirpath[d][n], 1) ; // bmp 
				}

		// look for valid INIs
				strcpy(string, string2) ;
				strcat(string, "INI Files in ") ;
				strcat(string, szSearchDir) ;
				SetWindowText(hArcDlg, string) ;

				for (j = 0 ; j < iIniDirs ; j++)
				{
					n = iIniDirIndex[j] ;	// there is one possibly-valid INI in this folder,
					d = iIniDirDepth[j] ;	// at this depth, and there may be others: seek them all out
					MaybeHere(hArcDlg, szDirpath[d][n], 2) ; 
				}
	if( useDATs)
	{
		// look for valid DATs
				strcpy(string, string2) ;
				strcat(string, "DAT Files in ") ;
				strcat(string, szSearchDir) ;
				SetWindowText(hArcDlg, string) ;

				for (j = 0 ; j < iDatDirs ; j++)
				{
					n = iDatDirIndex[j] ;	// there is one possibly-valid DAT in this folder,
					d = iDatDirDepth[j] ;	// at this depth, and there may be others: seek them all out
					MaybeHere(hArcDlg, szDirpath[d][n], 3) ; 
				}
	}

		// look for valid TRKs
				strcpy(string, string2) ;
				strcat(string, "TRK Files in ") ;
				strcat(string, szSearchDir) ;
				SetWindowText(hArcDlg, string) ;

				for (j = 0 ; j < iTrkDirs ; j++)
				{
					d = iTrkDirDepth[j] ;	// there is one possibly-valid TRK in this folder,
					n = iTrkDirIndex[j] ;	// at this depth, and there may be others: seek them all out
					MaybeHere(hArcDlg, szDirpath[d][n], 4) ; 
				}

			SetWindowText(hArcDlg, "The Archivist is Sorting the Results of the Search") ;
			SetWindowText(GetDlgItem(hDlg, IDC_S_DOINGDRIVE), "Sorting...") ;
			GetIDsperIMG() ;				// get the IDs corresponding to extant images
		    T.iNumTreeItems[0] = T.iNumTreeItems[1] = T.iTotTreeItems = 0 ;
			UpdateTrees() ;

			// search completed, so
			// flag up the completion
			searching = 0 ;
			 searched = 1 ;
			// reset progress bars
			SendMessage(hWndPB2, PBM_SETPOS, (WPARAM) 0, 0) ;
			SendMessage(hWndPB3, PBM_SETPOS, (WPARAM) 0, 0) ;
			// clear the most recent "found" reports
			//SetWindowText(GetDlgItem(hDlg, IDC_S_FOUND), "" ) ;
			//SetWindowText(GetDlgItem(hDlg, IDC_S_SUITE), "" ) ;

			// and say that we're done
			strcpy(string, "The Archivist is working with ") ;
			strcat(string, szUsingArchive) ;
			SetWindowText(hArcDlg, string) ;
			SetWindowText(GetDlgItem(hDlg, IDC_S_DOINGDRIVE), "Done!") ;

		} // end of Search System
		break ;

	default:
		break ;

	} //switch(LOWORD(wParam)

	break ; // for WM_COMMAND

	default:
		break ;
	
	} // switch(msg)

	return FALSE ;
} // End of ArchivistDlgProc()

long CALLBACK  PreviewProc(hWnd, message, wParam, lParam)
HWND hWnd;                      /* window handle                 */
UINT message;                   /* type of message               */
WPARAM wParam;                  /* additional information        */
LPARAM lParam;                  /* additional information        */
{
	PAINTSTRUCT ps ;

	switch(message)
	{
      case WM_NCHITTEST: // works for a mouse event anywhere in this window

	// If the mouse has moved window, tell the abandoned window so that
	// it can turn off any tip that it might have showing, then make
	// this window officially current. Else preserve status quo.
	if (hWnd != CurrentWindow)
	{
		SendMessage(CurrentWindow,WM_COMMAND,WM_MOUSEGONE,0L) ;
		CurrentWindow = hWnd ;
	}

	// The hit test must be passed
	// to the default window proc.
			return (DefWindowProc(hWnd, message, wParam, lParam)) ;

	case WM_COMMAND:

		switch (LOWORD(wParam))
	{
	case WM_MOUSEGONE:  // mouse has gone from THIS window
		// get rid of any tip showing
		   if (CurrentTip != (HWND)NULL)
		   RemoveTip() ;
		   return 0L ;

	default: break ;

	} // end switch (LOWORD(wParam))

		break ; // for WM_COMMAND

	case WM_PAINT:
		{
				HDC hdc, hmemDC ;
			   RECT rc ;
			HBITMAP oBm ;
			   UINT wd, ht, Wd, Ht, WD, HT ;

		hdc = BeginPaint(hWnd, &ps) ;

		GetClientRect(hWnd, &rc) ;

			   Wd = rc.right - rc.left ;
			   Ht = rc.bottom - rc.top ;

		hmemDC = CreateCompatibleDC(hdc) ;

	if (hWnd == hWndPvw)
	{
		if (showpreview)
		{
			oBm = SelectObject(hmemDC, hPreview) ;
			 wd = WD = wPrview ;
			 ht = HT = hPrview ;
		}
		else
		{
			oBm = SelectObject(hmemDC, hDefault) ;
			 wd = Wd ; WD = 70 ;
			 ht = Ht ; HT = 80 ;
		}
	}

	if (hWnd == hWndGrb)
	{
			oBm = SelectObject(hmemDC, hGrab) ;
			wd = WD = wGrb ;
			ht = HT = hGrb ;
	}

				while ( wd > Wd || ht > Ht )
				{
					wd-- ;
					ht = MulDiv(wd, HT, WD) ;
				}

				while ( wd < Wd && ht < Ht )
				{
					wd++ ;
					ht = MulDiv(wd, HT, WD) ;
				}

		SetStretchBltMode(hdc, COLORONCOLOR) ;
			
		StretchBlt( hdc,			// Destination DC
					0,				// x Top Left Corner destination
					0,				// y TLC destination
					wd, ht,			// pixel width & height in destination
					hmemDC,			// Source DC
					0, 0,			// x,y TLC source
					WD, HT,			// width & height in source
					SRCCOPY );		// raster operation (copy)

		SelectObject(hmemDC, oBm) ;
		DeleteDC( hmemDC ) ;				  // clear up

		EndPaint(hWnd, &ps) ;
		}
		return 0 ;
 
        default:                  /* Passes it on if unprocessed    */
            return (DefWindowProc(hWnd, message, wParam, lParam));
	}
 return ((long)NULL) ;
}

void KillDipControls( void )
{
	 KillArcDipControls() ;
	KillRastDipControls() ;
}

void KillArcDipControls( void ) 
{
			CheckDlgButton(hDlgDisplay, IDC_C_RAWDIPS,        BST_UNCHECKED) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MEANDIPS,       BST_UNCHECKED) ;
			CheckDlgButton(hDlgDisplay, IDC_C_RAWTUNEDDIPS,   BST_UNCHECKED) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MEANTUNEDDIPS,  BST_UNCHECKED) ;
			CheckDlgButton(hDlgDisplay, IDC_C_RAWPEAKS,       BST_UNCHECKED) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MEANPEAKS,      BST_UNCHECKED) ;
			CheckDlgButton(hDlgDisplay, IDC_C_RAWTUNEDPEAKS,  BST_UNCHECKED) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MEANTUNEDPEAKS, BST_UNCHECKED) ;
			updisp();

			EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RAWDIPS ),       FALSE) ;
			EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MEANDIPS),       FALSE) ;
			EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RAWTUNEDDIPS ),  FALSE) ;
			EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MEANTUNEDDIPS),  FALSE) ;
			EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RAWPEAKS),       FALSE) ;
			EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MEANPEAKS),      FALSE) ;
			EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RAWTUNEDPEAKS ), FALSE) ;
			EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MEANTUNEDPEAKS), FALSE) ;
}

void KillRastDipControls( void )
{
			CheckDlgButton(hRastDlg, IDC_C_SYNTH_RAW_DIPS,   BST_UNCHECKED) ;
			CheckDlgButton(hRastDlg, IDC_C_SYNTH_MEAN_DIPS,  BST_UNCHECKED) ;
			CheckDlgButton(hRastDlg, IDC_C_TUNED_RAW_DIPS,   BST_UNCHECKED) ;
			CheckDlgButton(hRastDlg, IDC_C_TUNED_MEAN_DIPS,  BST_UNCHECKED) ;
			CheckDlgButton(hRastDlg, IDC_C_SYNTH_RAW_PEAKS,  BST_UNCHECKED) ;
			CheckDlgButton(hRastDlg, IDC_C_SYNTH_MEAN_PEAKS, BST_UNCHECKED) ;
			CheckDlgButton(hRastDlg, IDC_C_TUNED_RAW_PEAKS,  BST_UNCHECKED) ;
			CheckDlgButton(hRastDlg, IDC_C_TUNED_MEAN_PEAKS, BST_UNCHECKED) ;
			updisp() ;

			EnableWindow(GetDlgItem(hRastDlg, IDC_C_SYNTH_RAW_DIPS),   FALSE) ;
			EnableWindow(GetDlgItem(hRastDlg, IDC_C_SYNTH_MEAN_DIPS),  FALSE) ;
			EnableWindow(GetDlgItem(hRastDlg, IDC_C_TUNED_RAW_DIPS ),  FALSE) ;
			EnableWindow(GetDlgItem(hRastDlg, IDC_C_TUNED_MEAN_DIPS),  FALSE) ;
			EnableWindow(GetDlgItem(hRastDlg, IDC_C_SYNTH_RAW_PEAKS),  FALSE) ;
			EnableWindow(GetDlgItem(hRastDlg, IDC_C_SYNTH_MEAN_PEAKS), FALSE) ;
			EnableWindow(GetDlgItem(hRastDlg, IDC_C_TUNED_RAW_PEAKS ), FALSE) ;
			EnableWindow(GetDlgItem(hRastDlg, IDC_C_TUNED_MEAN_PEAKS), FALSE) ;
}

void Refresh( void ) // for (re)builds not requiring a bud-data refresh
{

			     _is.AlignsExist = 0 ;			// need new alignment epochs
			  _is.modAlignsExist = 0 ;
				 _is.AlDataExist = 0 ;			// and new alignment data
				 _is.AllAlsExist = 0 ;           // need to refresh alignment groups
				  _is.AvelsExist = 0 ;           // need to refresh angular velocity difference
			   _is.CsqRateExists = 0 ;			// need to redo rate of change of alignment
			       _is.ImpsExist = 0 ;

			   _is.rAgraphExists = 0 ;			// new agraphs will be needed
			   _is.mAgraphExists = 0 ;	

		_is.LamSpExists   =						// new spectra, spectral peaks
		 _is.mLamSpExists  = 					// and tuned and untuned synthesese needed
		  _is.LamSnExists   =
		   _is.mLamSnExists  =
		    _is.LamFSnExists  =
			 _is.mLamFSnExists = 0 ; 
				 
	           _is.RawDipsExist = 0 ;		// Lambda dips and peaks need re-doing
	      _is.RawTunedDipsExist = 0 ;
		      _is.MeanDipsExist = 0 ;
	     _is.MeanTunedDipsExist = 0 ;
	          _is.RawPeaksExist = 0 ;
	     _is.RawTunedPeaksExist = 0 ;
		     _is.MeanPeaksExist = 0 ;
	    _is.MeanTunedPeaksExist = 0 ;

		// and the controls for dips and peaks need disabling

		KillDipControls() ;

		    if (pFourier != NULL)
		    {
			  pFourier->Peaks  =
			  pFourier->mPeaks = 0 ;
		    }

		       if (pAlFou != NULL)				// if we have the struct,
			   {								// Alignment Data, and related 
			     pAlFou->Peaks  =				// spectra and peaks need renewing
			     pAlFou->mPeaks =
				 _is.ALNSpExists = 0 ;
			   }

		       if (pIMFou != NULL)				// if we have the struct,
			   {								// Implied Period Data, and related 
			     pIMFou->Peaks  =				// spectra and peaks need renewing
			     pIMFou->mPeaks =
				 _is.IMPSpExists = 0 ;
			   }
}			


// OnChildDialogInit - Positions the child dialog box to fall 
//     within the display area of the tab control. 
 
VOID WINAPI OnChildDialogInit(HWND hDlg) 
{ 
    SetWindowPos(hDlg,
		         HWND_TOP, 
                 rcTabDisplay.left,
				 rcTabDisplay.top, 
                 0, 0, SWP_NOSIZE) ; 
}
 
VOID WINAPI OnSelChanged(HWND hwndDlg) 
{
	static HWND Old = NULL ;

	// hide the currently showing dialog

	if (Old != NULL)
	{
	 // if switching away from the Tuned dialog, and the
	 // Selectivity Curve is showing, turn it off and hide it.
	 if (Old == hDlgTuned) 
           SendMessage(hDlgTuned, CLOSEALL, 0, 0L) ;

 	 ShowWindow(Old, SW_HIDE) ;
	}

    // show the tab-selected child dialog box.

	switch (TabCtrl_GetCurSel(hWndTab))
	{
	case 0:
		{ int i ; char sel[100] ;
	Old = hDlgSource ;	ShowWindow(hDlgSource, SW_SHOW) ;	// show the dialog and get the current combo edit box selection
	SendDlgItemMessage(hDlgSource, IDC_CB_PFX, WM_GETTEXT, (WPARAM)100, (LPARAM)(LPCTSTR)sel) ;

	ClearCombo(hDlgSource, IDC_CB_PFX) ;					// clear the entire thing, then replace edit box selection
	SendDlgItemMessage(hDlgSource, IDC_CB_PFX, WM_SETTEXT,   (WPARAM)0, (LPARAM)(LPCTSTR)sel) ;

	for (i = 0 ; i < A.iPfxIDs ; i++)						// and refill the list, to pick up changes since last show
	PutInCombo(hDlgSource, IDC_CB_PFX, A.szKnownpfx[i]) ;
		}
	      break ;

	case  1:	Old = hDlgEpochs ;		ShowWindow(hDlgEpochs,		SW_SHOW) ;		break ;

	case  2:	Old = hDlgSelectBody ;	ShowWindow(hDlgSelectBody,	SW_SHOW) ;		break ;

	case  3:	Old = hDlgDisplay ;		ShowWindow(hDlgDisplay,		SW_SHOW) ;		break ;

	case  4:	Old = hDlgSystemicII ;	ShowWindow(hDlgSystemicII,	SW_SHOW) ;		break ;

	case  5:	Old = hDlgSystemic ;	ShowWindow(hDlgSystemic,	SW_SHOW) ;		break ;

	case  6:	Old = hDlgMisc ;		ShowWindow(hDlgMisc,		SW_SHOW) ;		break ;

	case  7:	Old = hDlgViewSet ;		ShowWindow(hDlgViewSet,		SW_SHOW) ;		break ;

	case  8:	Old = hDlgFourier ;		ShowWindow(hDlgFourier,		SW_SHOW) ;		break ;

	case  9:	Old = hDlgSpectra ;		ShowWindow(hDlgSpectra,		SW_SHOW) ;		break ;

	case 10:	Old = hDlgTuned ;		ShowWindow(hDlgTuned,		SW_SHOW) ;		break ;
	}
}
 
// This function is called from CtlPanelDlgProc, which is
// a modeless dialog box, created and initialised just once,
// and shown or hidden by ShowWindow(). Therefore this
// function is called only once, too. 

VOID WINAPI OnTabbedDialogInit(HWND hwndDlg) 
{ 
    TC_ITEM tie;
    DWORD dwDlgBase = GetDialogBaseUnits() ; 
    int cxMargin = LOWORD(dwDlgBase) / 4 ; 
    int cyMargin = HIWORD(dwDlgBase) / 8 ; 
	
	// hWndTab and rcTab are globals
	// assigned by CtlPanelDlgProc.

	//CreateImage_List
 
   // Add a tab for each of the child dialog boxes.
	
    tie.mask = TCIF_TEXT | TCIF_IMAGE ; 
    tie.iImage = -1;
	
    tie.pszText = "Source"; 
    TabCtrl_InsertItem(hWndTab, 0, &tie); 

    tie.pszText = "Epochs"; 
    TabCtrl_InsertItem(hWndTab, 1, &tie);

	tie.pszText = "Bodies" ;
    TabCtrl_InsertItem(hWndTab, 2, &tie);

    tie.pszText = "Task"; 
    TabCtrl_InsertItem(hWndTab, 3, &tie);

	tie.pszText = "Prediction" ;
    TabCtrl_InsertItem(hWndTab, 4, &tie);

    tie.pszText = "Ephemeris."; 
    TabCtrl_InsertItem(hWndTab, 5, &tie);

    tie.pszText = "Raster"; 
    TabCtrl_InsertItem(hWndTab, 6, &tie);

	tie.pszText = "Visualise" ;
    TabCtrl_InsertItem(hWndTab, 7, &tie);

    tie.pszText = "Fourier"; 
    TabCtrl_InsertItem(hWndTab, 8, &tie);
	
    tie.pszText = "Spectra"; 
    TabCtrl_InsertItem(hWndTab, 9, &tie);

    tie.pszText = "Tuned"; 
    TabCtrl_InsertItem(hWndTab, 10, &tie);
	
   // Calculate the display rectangle.
    OffsetRect(&rcTab,
		       cxMargin - rcTab.left, 
               cyMargin - rcTab.top) ; 
 
    CopyRect(&rcTabDisplay, &rcTab);
	
    TabCtrl_AdjustRect(hWndTab, FALSE, &rcTabDisplay);
	
	    // Set the size and position of the tab control
	// in the Control Panel
	
    SetWindowPos(hWndTab,
		         NULL,
				 rcTab.left,
				 rcTab.top, 
                 rcTab.right  - rcTab.left,
				 rcTab.bottom - rcTab.top, 
                 SWP_NOZORDER);

	
 	// Might as well create the dialogs now. It'll happen just once,
	// each dialog will be initialised just once on the start-up
	// defaults, content changes will hold from use to use,
	// and from the outset the dialog handles will be globally
	// available for inter-dialog communications. Seems a good plan!

	// CAVEAT: this may mean that refreshes that should occur do not occur.

        hDlgSelectBody = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_SELECTBODY),
		hwndDlg, TabSelectBodyDlgProc) ;		// Select Body

        hDlgEpochs = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_EPOCHS),
		hwndDlg, TabEpochsDlgProc) ;			// Select Epochs

        hDlgDisplay = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_DISPLAY),
		hwndDlg, TabDisplayDlgProc) ;			// Select Tasks

        hDlgSystemic = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_SYSTEMIC),
		hwndDlg, TabSystemicDlgProc) ;			// Ephemeris

        hDlgSystemicII = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_SYSTEMIC2),
		hwndDlg, TabSystemicIIDlgProc) ;		// Predictions

        hDlgMisc = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_MISC),
		hwndDlg, TabMiscDlgProc) ;				// Raster				

        hDlgFourier = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_FOURIER),
		hwndDlg, TabFourierDlgProc) ;			// Fourier

        hDlgTuned = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_TUNED),
		hwndDlg, TabTunedDlgProc) ;				// Tuned

        hDlgSpectra = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_SPECTRA),
		hwndDlg, TabSpectraDlgProc) ;			// Spectra

        hDlgViewSet = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_VIEWSET),
		hwndDlg, TabViewSettingsDlgProc) ;		// Visualise


	// Do the "first" one last, as it wants
	// to set things in the others during
	// its initialisation, so they should
	// already exist.
        hDlgSource = CreateDialog(hInst, 
        MAKEINTRESOURCE(IDD_TC_EPS_SRC_BDY),
		hwndDlg, TabSourceDlgProc) ;			// Source of Data

    // Force selection of the first item.

	    TabCtrl_SetCurSel(hWndTab, 0) ; // select the tab
        OnSelChanged(hwndDlg);			// select the dialog into the control 
} 

BOOL CALLBACK CtlPanelDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	int i ;
	//static modWason = 0 ;
	LPSUITE ps ;
	HWND hD ;

	switch(msg)
	{
	case WM_INITDIALOG:

	CDlg = hDlg ;  // need a simple global

	// get the handle of the Progress bar (global for easy access)
	hWndPB1 = GetDlgItem(hDlg, IDC_PB) ;

    // set the range and initial position
	// of the Progress bar.
    SendMessage(hWndPB1, PBM_SETRANGE, 0, MAKELPARAM(0, 10000)) ;
    SendMessage(hWndPB1, PBM_SETPOS,  (WPARAM) 0, 0) ;

	// get handle of static control indicating what is being fetched
	hWndFetch = GetDlgItem(hDlg, IDC_S_INFO) ;
	SetWindowText(hWndFetch, "") ;

	// get the handle of the build button (global for easy access)
	hBuild = GetDlgItem(hDlg, IDC_B_BUILD) ;


			hD = GetDlgItem(hDlg, IDC_U_EP_DENSITY) ;

			SetUDRng(hD, 48, 1) ; 
			SetUDPos(hD, epdensity) ; 

  // Set the combo edit window to the current planet 
				SendDlgItemMessage(hDlg,
			               IDC_CB_BODY,
						   WM_SETTEXT,
						   (WPARAM)0,
						   (LPARAM)(LPCSTR)plname[UsePlanet]) ;

  // Fill up the combo list with planet names
     for ( i = 3 ; i <= 15 ; i++ )
   {
	if (i == 10 || (i > 11 && i < 15)) continue ;

    SendDlgItemMessage(
		               hDlg,
			           IDC_CB_BODY,
				       CB_ADDSTRING,
				      (WPARAM)0,
				      (LPARAM)(LPCTSTR)plname[i]
				      ) ;
   }

// Set frame
CheckRadioButton(hDlg, IDC_R_GEO,
				       IDC_R_EQU,
					   IDC_R_GEO) ;

SendMessage(GetDlgItem(hDlg,IDC_C_HOLD_FOR_ENABLE), BM_SETCHECK, BST_UNCHECKED, 0L) ;

	// get the handle of the Tab control (global for easy access)
	hWndTab = GetDlgItem(hDlg, IDC_TABCTL) ;

	// get Tab control's window size (global for easy access)
	GetWindowRect(hWndTab, &rcTab) ;

	// initialise the Tab control
	OnTabbedDialogInit(hDlg) ;

		return TRUE ; // WM_INITDIALOG

	case CLOSEALL:
		
	// if the Control Panel is being hidden, and
	// the Selectivity Curve is showing, turn off
	// and hide the Curve before hiding the Panel.

		   if (TabCtrl_GetCurSel(hWndTab) == 9)
		   {
			   if (IsDlgButtonChecked(hDlgTuned, IDC_C_SHOW_CURVE))
			   {
				   CheckDlgButton(hDlgTuned, IDC_C_SHOW_CURVE, 0) ;
				   ShowWindow(hWndTune, SW_HIDE) ;
			   }
		   }

	// if the Control Panel is being hidden, and
	// the PG raster is showing, turn off and hide the
	// raster and the raster's dialog box,
	// before hiding the Panel.

		   if (TabCtrl_GetCurSel(hWndTab) == 5)
		   {
			   if (IsDlgButtonChecked(hDlgSystemicII, IDC_C_PGRASTER))
			   {
				   CheckDlgButton(hDlgSystemicII, IDC_C_PGRASTER, 0) ;
				   ShowWindow(hWndRast, SW_HIDE) ;
				   ShowWindow(hRastDlg, SW_HIDE) ;
			   }
		   }

			break ;

	case WM_COMMAND:

		switch(LOWORD(wParam))
		{
			char buff[256] ;
			BOOL snafu ;

		case IDC_E_EP_DENSITY:
			epdensity = GetDlgItemInt(hDlg, IDC_E_EP_DENSITY, &snafu, FALSE) ;
			if (oepdensity != epdensity) updisp() ;
			break ;

		case IDC_CB_BODY:	 // we may have had a change of body

			// fetch changes to the name of the new body

				SendDlgItemMessage(hDlg,
			               IDC_CB_BODY,
						   WM_GETTEXT,
						   (WPARAM)20,
						   (LPARAM)CurrentBody) ;

			 // Get the wanted body's number

				for ( i = 3 ; i <= 11 ; i++ )  // Mercury to Sun (No Pluto)
				{
					int UseNext ;
					if (i == PLU) continue ;
					if (0 == strcmp(CurrentBody, plname[i]))
					{
						UseNext = i ;
						if (UseNext != UsePlanet) // has the body-selection changed?
						{
							BodyChanged = 1 ;		// yes it has
							UsePlanet = UseNext ;	// use it
						}
						else
						BodyChanged = 0 ;			// no change of body selection
					}
				}

	if (BodyChanged)
	{
						ps = A.pSuiteperpfx[CurrentPfxID][UseSuite] ;
						sprintf(buff," Data-Source: %s   -   %s lunar alignments with %s",
									ps->desc,
									framename[UseCentre],
									plname[UsePlanet]
										) ;

							ShowArchBar(hWndArch, buff) ;
							if (st.AllEpSet)
							EnableWindow(hBuild, TRUE) ;

		    // no bud-data (re)build needed
			// but alignments need to be (re)found.

			// Alignment Data needs (re)finding, as it is
			// derived from the relative positions of the
			// Moon and the new (changed) body.
				
			// As they depend on the number of alignments
			// found, the Fourier order bounds may change,
			// invalidating all spectra, spectral peaks
			// and synthesese based upon the bounds

				Refresh() ;

		    // and go get what's needed
			 SendMessage(hDlgSource, WM_COMMAND, IDC_B_BUILD, 0L) ;
}			
			break ;

		case IDC_FLYERS:
			doFlyers ^= 1 ;
			if (doFlyers) updisp() ;
			break ;

		case IDC_R_GEO:  // we have had a change of frame
		case IDC_R_EQU:

           if (st.AllEpSet) // if we have the epochs
			{
			// no bud-data (re)build is needed,
			// but the Fourier bounds may change,
			// invalidating all spectra and synthesese
			// based on their current values, and the
			// relationship of bud data to alignment
			// dates may change too, invalidating
			// current Agraphs.

			   Refresh() ;

		    // go get what's needed
			SendMessage(hDlgSource, WM_COMMAND, TG_GET_ALIGNS, 0L) ;

			// honour current requests

			updisp() ;

			}
			break ;

		case IDC_B_BUILD: // Build
		// Do Alignments and/or Data
			if (!_is.AlignsExist)
			SendMessage(hDlgSource, WM_COMMAND, TG_GET_ALIGNS, 0L) ;
			if (wantModanom && !_is.modAlignsExist)
			SendMessage(hDlgSource, WM_COMMAND, TG_GET_ALIGNS, 0L) ;
			if (!_is.DataExist) 
			SendMessage(hDlgSource, WM_COMMAND, TG_BUILD_DATA, 0L) ;
			updisp() ;

			break ;

		case IDC_B_ENABLE:
			//GoForIt = 1;
			//updisp() ;    // this needs changing
			//GoForIt = 0 ;
			break ;

		default:
			break ;
		}
		break ; // WM_COMMAND

	case WM_NOTIFY:
		{
		 LPNMHDR hdr ;
		 hdr = (LPNMHDR)lParam ;
		 switch(hdr->code)
		 {
		 case TCN_SELCHANGE:  // respond to change of dlg. tab selection
		 OnSelChanged(hDlg) ;
		     break ;
		 default:
			 break ;
		 }
	    } // WM_NOTIFY
		break ;


     default:
		break ;
	} // switch (msg)

	return FALSE ;
} // CtrlPanelDlgProc

//*****************************
//		Data Sources
//*****************************
BOOL CALLBACK TabSourceDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{

    static BOOL snafu, BO ;
	static BOOL T = TRUE, F = FALSE ;
			int i ;
		 static p ;
	static char buffer[260], buff[260], c ;
		 double ep1, ep2, epdiff, diff ;
	static long alignments ;
	LPSUITE ps ;

	switch (msg)
	{
	case WM_INITDIALOG: // !!! this happens just once, on first showing!!!
		 
if (SRCH & PLAM)       CheckRadioButton(hDlg,IDC_R_PRJLAM,
									         IDC_R_RGRLAM,
										     IDC_R_PRJLAM) ;

if (SRCH & RLAM)	   CheckRadioButton(hDlg,IDC_R_PRJLAM,
									         IDC_R_RGRLAM,
										     IDC_R_RGRLAM) ;

if (SRCH & LDIA)       CheckRadioButton(hDlg,IDC_R_ONDIA,
										     IDC_R_ONRYT,
										     IDC_R_ONDIA) ;

if (SRCH & LRYT)       CheckRadioButton(hDlg,IDC_R_ONDIA,
										     IDC_R_ONRYT,
										     IDC_R_ONRYT) ;

if (SRCH & LLFT)       CheckRadioButton(hDlg,IDC_R_ONDIA,
										     IDC_R_ONRYT,
										     IDC_R_ONLFT) ;

// Show current Prefix (first time in - there isn't one, yet) in Window title bar and combo edit box

      sprintf(buff, " Data-Source: None Selected." ) ;

		        ShowArchBar(hWndArch, buff) ;
				
         sprintf(buff, "None Selected") ;

				SendDlgItemMessage(hDlg,
			               IDC_CB_PFX,
						   WM_SETTEXT,
						  (WPARAM)0,
						  (LPARAM)(LPCSTR)buff) ;

	OnChildDialogInit(hDlg) ;

		return TRUE ; // WM_INITDIALOG

	case WM_TIMER:
		{
		static s ;
		switch(wParam)
		{
		case IDT_SELSUITE: // flash "select suite" message
			s ^= 1 ;
			ShowWindow(GetDlgItem(hDlg, IDC_S_SELSUITE), s ? TRUE : FALSE) ;
			break ;
		}

		return 0L ;
		}

 	   case WM_VSCROLL:  // Service up/down controls
// Since all u/d ctrls here are auto-buddy integer style,
// they are serviced automatically. No code is needed
// here just now.
		   break ;

case WM_COMMAND:

	switch( LOWORD(wParam))
	{
		case IDC_B_ALL:	 // all available instances wanted
			{
					HWND H = hDlgEpochs ;
			 LPBUDSEARCH B = BudSearch ;

		GetFirstandFinal(B, ALL) ;

    	SetDlgItemText(H,IDC_E_D1,		B->szBudDay1) ;
		SetDlgItemText(H,IDC_E_M1,		B->szBudMon1) ;
		SetDlgItemText(H,IDC_E_Y1,		B->szBudYr1 ) ;
		SetDlgItemText(H,IDC_E_HR1,		B->szBudHr1) ;
		SetDlgItemText(H,IDC_E_MIN1,	B->szBudMn1) ;
		SetDlgItemText(H,IDC_E_SEC1,	B->szBudSc1) ;

		SetDlgItemText(H,IDC_E_D2,		B->szBudDay2) ;
		SetDlgItemText(H,IDC_E_M2,		B->szBudMon2) ;
		SetDlgItemText(H,IDC_E_Y2,		B->szBudYr2 ) ;
		SetDlgItemText(H,IDC_E_HR2,		B->szBudHr2) ;
		SetDlgItemText(H,IDC_E_MIN2,	B->szBudMn2) ;
		SetDlgItemText(H,IDC_E_SEC2,	B->szBudSc2) ;


		// set general date bounds to the bud bounds by default
		SetDlgItemText(H,IDC_E_ASTD1,	B->szBudDay1) ;
		SetDlgItemText(H,IDC_E_ASTM1,	B->szBudMon1) ;
		SetDlgItemText(H,IDC_E_ASTY1,	B->szBudYr1 ) ;
		SetDlgItemText(H,IDC_E_ASTHR1,	B->szBudHr1 ) ;
		SetDlgItemText(H,IDC_E_ASTMIN1,	B->szBudMn1 ) ;
		SetDlgItemText(H,IDC_E_ASTSEC1,	B->szBudSc1 ) ;

		SetDlgItemText(H,IDC_E_ASTD2,	B->szBudDay2) ;
		SetDlgItemText(H,IDC_E_ASTM2,	B->szBudMon2) ;
		SetDlgItemText(H,IDC_E_ASTY2,	B->szBudYr2 ) ;
		SetDlgItemText(H,IDC_E_ASTHR2,	B->szBudHr2 ) ;
		SetDlgItemText(H,IDC_E_ASTMIN2,	B->szBudMn2 ) ;
		SetDlgItemText(H,IDC_E_ASTSEC2,	B->szBudSc2 ) ;

		for ( i = 0,
			  st.Ep1Set = st.Ep2Set = st.AllEpSet = 1 ;
		      i < 12 ; st.Set[i++] = 1 ) ;
			  checkeps() ;
		allowbuild = 1 ; // immediate
		SendMessage( hDlgSource, WM_COMMAND, TOTAL_REBUILD, 0L) ;
			}
		break ;

		   case TOTAL_REBUILD:

				  _is.DataExist = 0 ;	// lambda data
				 _is.MeansExist = 0 ;	// running mean lambda data

			    _is.AlignsExist = 0 ;	// lunar alignments for selected body
			 _is.modAlignsExist = 0 ;	// lunar alignments for selected body
				_is.AllAlsExist = 0 ;   // lunar alignments for all included bodies

			  _is.BodyDirsExist = 0 ;	// body directions
				_is.AlDataExist = 0 ;   // hi-res alignment data

			  _is.CsqRateExists = 0 ;	// cos squared (moon/planet angular difference)
			     _is.AvelsExist = 0 ;	// angular velocities
				  _is.ImpsExist = 0 ;	// implied periods

				   pSamp->Peaks = 0 ;	// raw lambda spectral peaks 
		          pSamp->mPeaks = 0 ;	// running mean lambda spectral peaks

			    _is.LamSpExists = 0 ;	// raw lambda spectrum
			   _is.mLamSpExists = 0 ;	// running mean lambda spectrum

			    _is.LamSnExists = 0 ;	// raw lambda synthesis
			   _is.mLamSnExists = 0 ;	// running mean lambda synthesis

			   _is.LamFSnExists = 0 ;	// forced raw lambda synthesis
			  _is.mLamFSnExists = 0 ;	// forced reunning mean lambda synthesis

			  _is.rAgraphExists = 0 ;	// raw lambda Agraph
			  _is.mAgraphExists = 0 ;	// running mean lambda Agraph

			    _is.ALNSpExists = 0 ;	// alignment spectrum
				_is.IMPSpExists = 0 ;	// implied period spectrum

	           _is.RawDipsExist = 0 ;
	      _is.RawTunedDipsExist = 0 ;
		      _is.MeanDipsExist = 0 ;
	     _is.MeanTunedDipsExist = 0 ;
	          _is.RawPeaksExist = 0 ;
	     _is.RawTunedPeaksExist = 0 ;
		     _is.MeanPeaksExist = 0 ;
	    _is.MeanTunedPeaksExist = 0 ;

		// turn off all dips/peaks on tuned or untuned synthesised lambda
		KillDipControls() ;

			  if (pFourier != NULL)
			  {
			   pFourier->Peaks = 0 ;
			  pFourier->mPeaks = 0 ;
			  }

			  if (pAlFou != NULL)
			  {
			   pAlFou->Peaks  = 0 ;
			   pAlFou->mPeaks = 0 ;
			  }

			  if (pIMFou != NULL)
			  {
			   pIMFou->Peaks  = 0 ;
			   pIMFou->mPeaks = 0 ;
			  }

			if (!allowbuild) // wait for build command
				EnableWindow(hBuild, TRUE) ;
			else // go build the data
			{
				// this fetches the alignments and hi-res alignment data 
				// according to general dates
				SendMessage(hDlg, WM_COMMAND, TG_GET_ALIGNS, 0L) ;

				// this fetches the bud-series data
				// according to the series dates
				SendMessage(hDlg, WM_COMMAND, TG_BUILD_DATA, 0L) ;
			}
			   break ;

		// A click on any in the following group indicates
		// a data rebuild is needed using current epochs.
		// There is no need to re-do alignments.

		case IDC_R_PRJLAM:
		case IDC_R_RGRLAM:
		case IDC_R_ONDIA:
		case IDC_R_ONRYT:
		case IDC_R_ONLFT:

			if (st.AllEpSet) // don't do it if epochs not ready
			{
		 _is.rAgraphExists = 0 ;					// new agraphs will be needed
		 _is.mAgraphExists = 0 ;
			 _is.DataExist = 0 ;					// new bud-data required
			_is.MeansExist = 0 ;					// signal that new means needed
		   _is.LamSpExists = 0 ;					// new lambda spectra needed
		  _is.mLamSpExists = 0 ;
		      pSamp->Peaks = 0 ;					// lambda spectral peaks need refinding
		     pSamp->mPeaks = 0 ;
		   _is.LamSnExists = 0 ;					// new lambda synthesese needed
	      _is.mLamSnExists = 0 ;
		  _is.LamFSnExists = 0 ;					// new forced lambda synthesese
		 _is.mLamFSnExists = 0 ;
	      _is.RawDipsExist = 0 ;					// new dips and peaks on Lambda tuned
	 _is.RawTunedDipsExist = 0 ;					// or untuned synthesese
		 _is.MeanDipsExist = 0 ;
	_is.MeanTunedDipsExist = 0 ;
	     _is.RawPeaksExist = 0 ;
	_is.RawTunedPeaksExist = 0 ;
		_is.MeanPeaksExist = 0 ;
   _is.MeanTunedPeaksExist = 0 ;

			KillDipControls() ;
			SendMessage(hDlg, WM_COMMAND, TG_BUILD_DATA, 0L) ;
            updisp() ;
			}
			break ;

		case IDC_B_USE_DEF_EPOS:  // NB - whether or not a bud has been selected
		SetDlgItemText(hDlgEpochs,IDC_E_ASTD1,   "01") ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTM1,   "01") ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTY1,   "1983" ) ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTHR1,  "12" ) ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTMIN1, "00" ) ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTSEC1, "00" ) ;

		SetDlgItemText(hDlgEpochs,IDC_E_ASTD2,   "01") ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTM2,   "01") ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTY2,   "2000" ) ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTHR2,  "00" ) ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTMIN2, "00" ) ;
		SetDlgItemText(hDlgEpochs,IDC_E_ASTSEC2, "00" ) ;
		AlignResolution = 0.2 ;
		checkeps() ;
		updisp() ;

			break ;

		case IDC_CB_SUITES: // select a suite from those of the selected prefix
			{
				LPSUITE ps ; // give this its own one
				int value ;
				value = SendDlgItemMessage(hDlg,
											IDC_CB_SUITES,
											CB_GETCURSEL,
											(WPARAM)0,
											(LPARAM)0) ;
				if (value == CB_ERR) // there is no selection
					{UseSuite = 0 ; break ;}
				else
				{
					 OldSuite = UseSuite ;
					 UseSuite = value ;
				}

			ps = A.pSuiteperpfx[CurrentPfxID][UseSuite] ; 

			sprintf(buff," Data-Source: %s   -   %s lunar alignments with %s",
						ps->desc,
						framename[UseCentre],
						plname[UsePlanet]
					) ;

			// copy to the title bar
			ShowArchBar(hWndArch, buff) ;
			// stop cueing
			KillTimer(hDlg, IDT_SELSUITE) ;
			// hide the cue
			ShowWindow(GetDlgItem(hDlg, IDC_S_SELSUITE), SW_HIDE) ;
			// allow load when suite selection is made
			EnableWindow(GetDlgItem(hDlg, IDC_B_ALL), TRUE) ;
			}
			break ;

		case IDC_CB_PFX:		 // is change in prefix combo edit box (selection made)
			{
				int q ;
			// disallow load until suite selection is made
				EnableWindow(GetDlgItem(hDlg, IDC_B_ALL), FALSE) ;
			// start "select suite" prompt flashing
				SetTimer(hDlg, IDT_SELSUITE, 250, NULL) ;			// quarter second
			// get the selection
				SendDlgItemMessage(hDlg,
			               IDC_CB_PFX,
						   WM_GETTEXT,
						   (WPARAM)260,
						   (LPARAM)(LPCSTR)buff) ;

			if (!strcmp(BudSearch->Prefix, buff)) // old and new are same
				break ;	
			else                                  // old and new differ
			{
			// A date reset and general rebuild
			// needed for this change.
			
			HavePrefix = 1 ;
			// copy the new prefix to the search struct
			strcpy(BudSearch->Prefix, buff) ;

			// get the prefix ID number from the archivist
			
			// we are getting a prefix for an archive operation,
			// not opening an instance in a suite: reset IsInst.
			IsInst = 0 ;
			for (i = 0 ; i < A.iPfxIDs ; i++)
			{
				if (!strcmp(buff, A.szKnownpfx[i]))
				{
					CurrentPfxID = i ;
					goto skip ;
				}
			}

skip:;
				ClearCombo(hDlg, IDC_CB_SUITES) ;

			// fill the suite combo with suites available for this bud 
			for (i = 0 ; i < A.iNumsuiperpfx[CurrentPfxID] ; i++)
			{
					ps = A.pSuiteperpfx[CurrentPfxID][i] ;
					InsInCombo(hDlg, IDC_CB_SUITES, ps->desc, i) ;
			}
			 // select the first available suite by default
				UseSuite = 0 ;
			}

				 q = A.iNumImgperpfx[CurrentPfxID] ;			// number of images in this series
				BudEp1 = A.fEpperpfx[CurrentPfxID][0] ;		// first bud data epoch, in days
				BudEp2 = A.fEpperpfx[CurrentPfxID][q-1] ;		// final bud data epoch, in days
				BudGP  = BudEp2 - BudEp1  ;					// grand period of bud data, in days

					ps = A.pSuiteperpfx[CurrentPfxID][UseSuite] ;	// find the given suite

		sprintf(buff," Data-Source: %s   -   %s lunar alignments with %s",
				    ps->desc,				// suite description
					framename[UseCentre],	// centre
					plname[UsePlanet]		// body
					) ;

			// copy to the title bar
			ShowArchBar(hWndArch, buff) ;

			// start with no dates set
			for (
				             i = 0,
				   st.AllEpSet = 0,
				     st.Ep1Set = 0,
				     st.Ep2Set = 0 ;
				   i < 7 ; 
				   st.Set[i++] = 0
				) ;

		 // Flag that we have switched to a new bud
			PrefixChange = 1 ;
			}
			break ;


		case TG_GET_ALIGNS:		// get alignment epochs (calls for hi res alignment data, too)

			if (st.AllEpSet) // if the epochs are all set
			{
				LPSUITE ps ;

		     SendMessage(hWndPB1, PBM_SETPOS,  (WPARAM) 0, 0) ;	// set progress bar
			 SetWindowText(hWndFetch,"Al. Epochs") ;

			align->epfirst  = ep1 = AstEp1 ;
			align->eplast   = ep2 = AstEp2 ;
			align->period   = AstGP ;
			align->interval = AlignResolution ; // Now settable in Preferences (25 Oct 2003)

			 if (align->period <= 0.0)
			 {
				 msgbox = 1 ;
			  MessageBox(hDlg,
				"The First Epoch is the same as or\n" \
				"is later than the Second.",
				"Bad Epochs",
				 MB_OK) ;
			     msgbox = 0 ;
				 goto leave ;
			 }

			 // get the frame
			 {
			 int UseNext ;
			 if (IsDlgButtonChecked(CDlg,IDC_R_GEO)) UseNext = GE ;
			 if (IsDlgButtonChecked(CDlg,IDC_R_EQU)) UseNext = EQ ;
		   //if (IsDlgButtonChecked(CDlg,IDC_R_HEL)) UseNext = HE ; // disabled for now

					FrameChanged = 0 ;
					if (UseNext != UseCentre)
					{
						FrameChanged = 1 ;
						align->centre = UseCentre = UseNext ;
					}
			 } 

			 ps = A.pSuiteperpfx[CurrentPfxID][UseSuite] ; // use the selected suite

			 sprintf(buff," Data-Source: %s  -  %s lunar alignments with %s",
					 ps->desc,				// the suite description embedded in the path
					 framename[UseCentre],
					 plname[UsePlanet]
					) ;

		  // copy to the title bar
			 ShowArchBar(hWndArch, buff) ;

				StartWait() ;

			   align->body = UsePlanet ;

			            ep = AstEp1 ;	// update elements to the starting epoch of the grand period
						update() ;

			   // Go find the lunar alignment epochs
			   // inside the general date bounds.
			    alignments = LunarAlign( UseCentre ) ;

				// BUGFIX: alignment indices and count now match !!!! 

				if (alignments >= 2) // If we have at least two
				{
				 // Find the mean inter-alignment interval
				 // and the largest and least IAPs.
				 for (
					      i =  1,
				  st.bigIAP = -1e10,
				  st.weeIAP =  1e10,
					 epdiff =  0.0 ;
				          i < alignments ;
				          i++ 
					 )
			{
			  epdiff += (diff = Date_Time[UsePlanet][i+1]->epal - Date_Time[UsePlanet][i]->epal) ;
			  st.bigIAP = diff > st.bigIAP ? diff : st.bigIAP ;
			  st.weeIAP = diff < st.weeIAP ? diff : st.weeIAP ;
			}

				// mean IAP inside the general date bounds				 
				  align->MeanAlIval = epdiff / (double)(alignments - 1) ;
			     // Good moment to calculate
				 // the Fourier order for the
				 // mean IAP.

				 // !!!!
				 // This is with respect to
				 // the astronomic grand period,
				 // not the Bud series grand period
				 // !!!!

				    st.pord = (ep2 - ep1) / align->MeanAlIval ;

				  // Also, get the orders for the least
				  // and largest IAPs 

				  st.ordforwee = (ep2 - ep1) / st.weeIAP ;
				  st.ordforbig = (ep2 - ep1) / st.bigIAP ;
				  st.ordrange = st.ordforwee - st.ordforbig ;

/*** I have never used these, so until I want to use them, let's not calculate them! 
				  // if we have a "raw" data set, we can calculate 
				  // the "raw" components for the mean, hi and lo IAPs.

				  if (_is.DataExist)
				  {
				  analysis(pFourier, bud, stash,    st.pord,      1) ;
				  analysis(pFourier, bud, stashbig, st.ordforbig, 1) ;
				  analysis(pFourier, bud, stashwee, st.ordforwee, 1) ;
				  }

				  // Similarly, if we have a "mean" data set, we can  
				  // calculate the "mean" components for the mean, hi 
				  // and lo IAPs.

				  if (_is.MeansExist)
				  {
				  analysis(pFourier, bud, mstash,    st.pord,      0) ;
				  analysis(pFourier, bud, mstashbig, st.ordforbig, 0) ;
				  analysis(pFourier, bud, mstashwee, st.ordforwee, 0) ;
				  }
***/
				}
				else // Is one alignment, or none
				{
					align->MeanAlIval = 0.0 ;

				 // Set pord to a default
				 // corresponding to a mean
				 // IAP of exactly 14 days.

		          st.pord = (ep2 - ep1) / 14.0 ;
				  st.ATopOrd = st.pord * 2.0 ;
		          sprintf(buff,"%7.6f", st.ATopOrd) ;
		          SetDlgItemText(hDlgFourier, IDC_E_ASTHORD, buff) ;
				  st.AOrdStep = (st.ATopOrd - st.ABotOrd) / 500.0 ;
				}

				// reset ep to earliest general date bound
				// and update elements to it, ready for
				// getting hi-res alignments
				       ep = ep1 ;
				       update() ;

		// get the high resolution alignment data
		SendMessage(hDlgSource, WM_COMMAND, GET_ALIGN_DATA, 0L) ;

		// we can now set the Fourier bounds and the resonant order, for both the bud-series
		// and the general dates, to correspond to the max alignment order of the current body.
		{
				// If we have a new bud (as opposed
				// to a new instance) and if override
				// permission has been with-held (under
				//'preferences'),then disallow override
				// of the default Fourier bounds.  

					if (PrefixChange)
					{
						PrefixChange = 0 ;
						if (!PermitOverRideOnNew) goto NoOverRide ;
					}
					//goto NoOverRide ;
						if (st.BTopOrd != ceil(2.0 * resorderbud)
							 ||
							st.BBotOrd != 0.0)
						{
						  UINT Usersays ;
						  char str[255] ;
                        sprintf(str,
                               "Unless over-ridden, the current\n" \
                               "top and bottom bud series Fourier orders,\n\n" \
                               "   top = %4.2f, bottom = %4.2f,\n\n" \
                               "will now change to new defaults.\n\n" \
                               "Do you wish to use\n" \
                               "the new values?\n",
                                st.BTopOrd, st.BBotOrd			// current values
	                           ) ;
						msgbox = 1 ;
                         Usersays = MessageBox(NULL,
							        str,
                                   "Top and Bottom Fourier-Order Change",
                                    MB_ICONEXCLAMATION|MB_YESNO
							        ) ;
						 msgbox = 0 ;

		               if ( Usersays == IDYES )	
						  {	
						   // Apply new Fourier bounds.

NoOverRide:			   resorder = pAlFou->bigOrd ;				// default for non-bud ops
					resorderbud = BudGP * resorder / AstGP ;	// corresponding bud-series resonant order

					if (FilterLP)
					{
					// Set the high order such that Very High Frequency (VHF)
					// components with periods equal to or less than LoPer
					// days are auto-excluded from the synthesese.
					   st.BTopOrd = BudGP / LoPer  ;
					  st.ATopOrd = AstGP * st.BTopOrd / BudGP ; // automatch
					}
					else
					{
					// Set the top Ast Fourier order to twice the current Almax order
					  st.ATopOrd = ceil(2.0 * resorder) ;
					  st.BTopOrd = BudGP * st.ATopOrd / AstGP ; // automatch
					}

					if (FilterHP)
					{
					st.BBotOrd = BudGP / HiPer  ;
					st.ABotOrd = AstGP * st.BBotOrd / BudGP ; // automatch
					}
					else	// Set the bottom Fourier orders to zero.
					st.BBotOrd = st.ABotOrd = 0.0 ;

				  st.AOrdStep = (st.ATopOrd - st.ABotOrd) / 500.0 ;	// Astron. Series order range
				  st.BOrdStep = (st.BTopOrd - st.BBotOrd) / 500.0 ;	//     Bud Series order range

		          sprintf(buff, "%7.6f", st.ATopOrd) ;
		          SetDlgItemText(hDlgFourier, IDC_E_ASTHORD, buff) ;

		          sprintf(buff, "%7.6f", st.ABotOrd) ;
		          SetDlgItemText(hDlgFourier, IDC_E_ASTLORD, buff) ;

		          sprintf(buff, "%7.6f", st.BTopOrd) ;
		          SetDlgItemText(hDlgFourier, IDC_E_HORD, buff) ;

		          sprintf(buff, "%7.6f", st.BBotOrd) ;
		          SetDlgItemText(hDlgFourier, IDC_E_LORD, buff) ;
						  }
					   // else leave them alone
						}
				}

				if (alignments >= 1) // If we have at least one lunar alignment
				{
					_is.AlignsExist = 1 ;
					if (wantModanom)		// if we have asked for modified alignments
					_is.modAlignsExist = 1 ;

					if (_is.DataExist)
					EnableWindow(hBuild, FALSE) ;
                    updisp() ;
				}
				else				// There are no lunar alignments
				{
					_is.AlignsExist = 0 ;
					if (wantModanom)		// if we have asked for modified alignments
					_is.modAlignsExist = 0 ;

					if (_is.DataExist)
					EnableWindow(hBuild, FALSE) ;

					msgbox = 1 ;
					MessageBox( NULL,
					"No Alignments found in\n" \
					"the given Data Period.",
					"Find Alignments.",
					MB_OK) ;
					msgbox = 0 ;
				}

leave:				EndWait() ;
			}
			else
			{
				msgbox = 1 ;
				MessageBox( NULL,
				"Epochs Not Ready.",
				"Find Alignments.",
				MB_OK) ;
				msgbox = 0 ;
			}

			break ;

        case GET_ALIGN_DATA:

			   // Get the hi-res alignment data for the general grand period

		if (!_is.AlDataExist) // Allocate if no Alignment data yet, or if it's invalidated
		{
				if (pAlFou != NULL) GlobalFree( pAlFou ) ;
                if (
	                (
	                 pAlFou = (LPFOURIER)GlobalAlloc(GPTR, sizeof(FOURIER))
	                ) == NULL 
                   ) 
        {
		 msgbox = 1 ;
		 MessageBox(
			        NULL,
		           "Can't Create the AlData Fourier Struct.",
				   "Alignment-Data Collection.",
				    MB_ICONEXCLAMATION | MB_OK
				   ) ;
		 msgbox = 0 ;
		 // Need a recovery here. Prog. will crash, else. 
	               //return 0 ;
        }
		}

		// zero the progress bar
        if (hWndPB1 != NULL)
        SendMessage(hWndPB1, PBM_SETPOS, (WPARAM)0, 0) ;
		SetWindowText(hWndFetch,"Hi-Res Align'ts") ;

		// go get the data

		_is.AlDataExist = GetAlignmentData( UseCentre,
			                               &(st.AOrdStep),
										   st.ATopOrd,
										   st.ABotOrd,
										   pAlFou
										   ) ;

			break ;

	// Fetch the bud-series data

		case TG_BUILD_DATA:

			// flag that data is not ready
				       DataReady = 0 ;

			// zero the progress bar
            SendMessage(hWndPB1, PBM_SETPOS, (WPARAM) 0, 0) ;
			SetWindowText(hWndFetch,"Bud Information") ;

			// Disable the controls
			EnableRwDspCtls( F ) ;
			EnableMnDspCtls( F ) ;

			// match dates by default
			SendMessage(hDlgEpochs, WM_COMMAND, IDC_B_MATCH_TO_BUD_SERIES, 0L) ;

			// Prevent unwanted ops,
			// and keep unwanted items out
			WantFile   = AskName    = UseBudID = 0 ;	// only Lambdas wanted
			OrderInSet = DayOfMonth = 0 ;
			     SRCH &= ~IPDS ;		                // no IPDs
			     SRCH &= ~MRDS ;		                // no MRDs
			// Now set up for what's actually wanted
			if (IsDlgButtonChecked(hDlg,IDC_R_PRJLAM))	// projective style
				SRCH |= PLAM ; else SRCH &= ~PLAM ;
			
			if (IsDlgButtonChecked(hDlg,IDC_R_RGRLAM))	// regression style
				SRCH |= RLAM ; else SRCH &= ~RLAM ;

			if (IsDlgButtonChecked(hDlg,IDC_R_ONDIA))	// diameters 
				SRCH |= LDIA ; else SRCH &= ~LDIA ;

			if (IsDlgButtonChecked(hDlg,IDC_R_ONLFT))	// left radii
				SRCH |= LLFT ; else SRCH &= ~LLFT ;

			if (IsDlgButtonChecked(hDlg,IDC_R_ONRYT))	// right radii
				SRCH |= LRYT ; else SRCH &= ~LRYT ;

			// Show we're busy
			StartWait() ;

			BO = (Inventory(BudSearch)) ? TRUE : FALSE ;

			// If inventory() successful,
			// enable Fourier specification controls,
			// else disable them.

				EnableWindow(GetDlgItem(hDlgFourier,IDC_E_LORD), BO) ;
				EnableWindow(GetDlgItem(hDlgFourier,IDC_U_LORD), BO) ;
				EnableWindow(GetDlgItem(hDlgFourier,IDC_E_HORD), BO) ;
				EnableWindow(GetDlgItem(hDlgFourier,IDC_U_HORD), BO) ;

				EnableWindow(GetDlgItem(hDlgFourier,IDC_E_ASTLORD), BO) ;
				EnableWindow(GetDlgItem(hDlgFourier,IDC_U_ASTLORD), BO) ;
				EnableWindow(GetDlgItem(hDlgFourier,IDC_E_ASTHORD), BO) ;
				EnableWindow(GetDlgItem(hDlgFourier,IDC_U_ASTHORD), BO) ;

				EnableWindow(GetDlgItem(hDlgDisplay,IDC_C_ORDLINES),  BO) ;

			if (BO == TRUE) // If the inventory has worked
			{
				// Tell us how many data items there are
				sprintf(buff, "%d", bud) ;
				SetDlgItemText(CDlg, IDC_E_ITEMS, buff) ;
				// Warn of too many instances
				if ( bud > MAXBUDS )
				{
					msgbox = 1 ;
					MessageBox(NULL, "Inventory: Allowed Number of Instances Exceeded.",
						             "Too many instances",
									  MB_ICONHAND|MB_APPLMODAL|MB_OK
							  ) ;
					msgbox = 0 ;
				}
				// Get rid of any old Fourier struct
				if (pFourier != NULL)
				{
					GlobalFree(pFourier) ;
					pFourier = NULL ;
				}
			   // Make a new Fourier struct
	if ((pFourier = (LPFOURIER)GlobalAlloc(GPTR,sizeof(FOURIER)))!= NULL)
	           {
		// If that worked....
				// Fill up the list. Indices start at 1
		        for ( i = 1,
					  pFourier->Hidata  = -1e5,	// prepare hi/lo search
					  pFourier->Lodata  =  1e5 ;
				      i <= bud ;
					  i++ )
				{
			   // Convert and copy to the !!ZERO-BASED!! Fourier data array.
				  strcpy(buff,szBudItems[i]) ;
				  pFourier->data[i-1] = atof(buff) ;
				}
				_is.DataExist = 1 ; // Lambda data available now

				if (wantMovingMean) // we want the moving mean data
				{
					    _is.MeansExist = 0 ; // say they don't exist to wipe old ones
						SendMessage(hDlg, WM_COMMAND, TG_MOVMEAN, 0L) ;	// go get 'em.
						EnableMnDspCtls( T ) ; // enable requests for moving mean features
				}

			   // Greatest and Least Data values. These indices
			   // start at zero, and end at bud-1.

				for ( i = 0,
					pFourier->mHidata = -1e5 ,
					pFourier->mLodata =  1e5 ,
					pFourier->Hidata  = -1e5 ,
					pFourier->Lodata  =  1e5 ;
					  i < bud ;
					  i++ )
				{
				  pFourier->Hidata = 
					  (pFourier->data[i] >= pFourier->Hidata) ? 
					   pFourier->data[i] :  pFourier->Hidata ;

				  pFourier->Lodata = 
					  (pFourier->data[i] < pFourier->Lodata) ? 
					   pFourier->data[i] : pFourier->Lodata ;

				  if (_is.MeansExist)
				  {
				  pFourier->mHidata = 
					  (pFourier->mdata[i] >= pFourier->mHidata) ? 
					   pFourier->mdata[i] :  pFourier->mHidata ;

				  pFourier->mLodata = 
					  (pFourier->mdata[i] < pFourier->mLodata) ? 
					   pFourier->mdata[i] : pFourier->mLodata ;
				  }
				}
			   // the alignments are in place
			   // get the "raw" component at the mean IAP order.
			    analysis(pFourier, bud, stash, st.pord, 1) ;

			   // We should be ready to do our stuff.
				DataReady = 1 ;
				EnableRwDspCtls( T ) ; // enable "Raw" controls
				// if we want moving mean data
				if (wantMovingMean && !_is.MeansExist )    
				{
				_is.MeansExist = RunningMean
						        (
						         bud,
						         MeanSpan,
						         pFourier
						        ) ;
				  EnableMnDspCtls( T ) ; // enable requests for moving mean features
				}
			   // Update the displays
			   // updisp() ;
				  if (PlotRaster)
				  {
					  RECT r ;
					  GetClientRect(hWndRast, &r) ;
					  ivrc(hWndRast, &r, TRUE) ;
				  }
	           }
	        else // Damn and blast, we messed up the allocation.
			{
				msgbox = 1 ;
				MessageBox(hDlg,
				           "allocation failure",
						   "Fourier Struct Allocation",
						    MB_OK) ;
				msgbox = 0 ;
			}
				// Disable the Build button in any case
				EnableWindow(hBuild, F) ;
			}
			// show we're not so busy now
			EndWait() ;
			break ;

		   default:
			   break ;

	} // switch (LOWORD(wParam))
	 
	break ; // for case WM_COMMAND


	default:
		break ;
	} // switch(msg)

  return FALSE ;
} // TabSource

void EnableMnDspCtls(BOOL B)
		{
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_S_OF2),     B) ;
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MDAT),    B) ;
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MSYN),    B) ;
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MCMP),    B) ;
		  EnableWindow(GetDlgItem(hDlgSpectra, IDC_C_MSPC),    B) ;
		  EnableWindow(GetDlgItem(hDlgSpectra, IDC_C_MASPC),   B) ;
		  EnableWindow(GetDlgItem(hDlgSpectra, IDC_C_MPHA),    B) ;
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MAGR),    B) ;
          EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_MFSYNTH), B) ;
		}

void EnableRwDspCtls(BOOL B)
		{
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RDAT),    B) ;
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RSYN),    B) ;
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RCMP),    B) ;
		  EnableWindow(GetDlgItem(hDlgSpectra, IDC_C_RSPC),    B) ;
		  EnableWindow(GetDlgItem(hDlgSpectra, IDC_C_RASPC),   B) ;
		  EnableWindow(GetDlgItem(hDlgSpectra, IDC_C_RPHA),    B) ;
		  EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RAGR),    B) ;
          EnableWindow(GetDlgItem(hDlgDisplay, IDC_C_RFSYNTH), B) ;
		}

#include "GetSynthesesandSpectra.h"

/*******************************************************************
						Sampler

  Regularise a time series with non-uniform time distribution
 (the series will always be a bud series - so, info. from Archivist
  and from the corresponding Fourier struct).
 
 *******************************************************************/
void Sampler
(
LPFOURIER D,	// pointer to the struct holding the input data set
LPFOURIER S,	// pointer to the struct holding the output data set
	  int s,	// number of samples in sample set
	  int raw	// select lambda-set 
)
{
	int N ;				// number of data points in the input set
	double fep, lep ;	// first and last ep's of input set
	double ival ;		// sampling time interval
	int j, k ;

	// number of data items in the input set
	//(same as the number of images corresponding to the prefix)
	N = A.iNumImgperpfx[CurrentPfxID] ;  

	// first and last sample points same as
	// first and last input data points
	fep = A.fEpperpfx[CurrentPfxID][0] ;
	lep = A.fEpperpfx[CurrentPfxID][N-1] ;

	if (raw)
	{
	 S->data[0]   = D->data[0] ;
	 S->data[s-1] = D->data[N-1] ;
	}
	else
	{
	S->mdata[0]   = D->mdata[0] ;
	S->mdata[s-1] = D->mdata[N-1] ;
	}
			 ival = (lep - fep) / (double)s ;
		 S->items = s ;

		for (j = 1 ; j < s ; j++)
		{
			double e ;
			e = (double)j * ival + fep ; // sampling ep
			for ( k = 0 ; k < N - 1 ; k++)
			{
				double e1, e2 ;
		if (e >= (e1 = A.fEpperpfx[CurrentPfxID][k]) &&
			e <  (e2 = A.fEpperpfx[CurrentPfxID][k + 1]))
				{
					double v1, v2, ed, vd ;
					ed = e2 - e1 ;
					if (raw) // use raw lambdas
					{
						v1 = D->data[k] ; v2 = D->data[k+1] ;
						vd = v2 - v1 ;
						S->data[j] = vd * (e - e1) / ed + v1 ;
					}
					else	// use running mean lambdas
					{
						v1 = D->mdata[k] ; v2 = D->mdata[k+1] ;
						vd = v2 - v1 ;
						S->mdata[j] = vd * (e - e1) / ed + v1 ;
					}
				} // if (e
			} // for (k
		} // for (j
}// Sampler()

void VelsOn( void )
{
	if (!VELS) VELS = 1 ; vcount++ ; // if VELS not set, set it now.
	return ;						 // In any case, increment usage count.
}

void VelsOff( void )
{
	if (VELS && vcount) vcount-- ;  // if vcount not already zero, decrement it
	if (!vcount) VELS = 0 ;         // turn off VELS only if nothing is using them
	return ;
}

BOOL CALLBACK TabSelectBodyDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	switch(msg)
	{
	case WM_INITDIALOG:

	OnChildDialogInit(hDlg) ;

		return TRUE ;

	case WM_COMMAND:

		switch(wParam)
		{

	// Select/Deselect into "System"
		case IDC_B_SYS_ALL_BODIES:
			{
			int b, ID ;
			for (b = EAR ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case EAR: ID = IDC_C_EAR  ; break ;
					case MOO: ID = IDC_C_MOO  ; break ;
					case SUN: ID = IDC_C_SUN  ; break ;
					case MER: ID = IDC_C_MER  ; break ;
					case VEN: ID = IDC_C_VEN  ; break ;
					case MAR: ID = IDC_C_MAR  ; break ;
					case JUP: ID = IDC_C_JUP  ; break ;
					case SAT: ID = IDC_C_SAT  ; break ;
					case URA: ID = IDC_C_URA  ; break ;
					case NEP: ID = IDC_C_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_CHECKED) ;
				BodyList[b] = 1 ;
				}
			updisp() ;
			}
			break ;

		case IDC_B_SYS_NO_BODIES:
			{
			int b, ID ;
			for (b = EAR ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case EAR: ID = IDC_C_EAR  ; break ;
					case MOO: ID = IDC_C_MOO  ; break ;
					case SUN: ID = IDC_C_SUN  ; break ;
					case MER: ID = IDC_C_MER  ; break ;
					case VEN: ID = IDC_C_VEN  ; break ;
					case MAR: ID = IDC_C_MAR  ; break ;
					case JUP: ID = IDC_C_JUP  ; break ;
					case SAT: ID = IDC_C_SAT  ; break ;
					case URA: ID = IDC_C_URA  ; break ;
					case NEP: ID = IDC_C_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_UNCHECKED) ;
				BodyList[b] = 0 ;
				}
			updisp() ;
			}
			break ;

		case IDC_C_SUN:
			BodyList[SUN] = IsDlgButtonChecked(hDlg, IDC_C_SUN) ;
			updisp() ;
			break ;

		case IDC_C_EAR:
			BodyList[EAR] = IsDlgButtonChecked(hDlg, IDC_C_EAR) ;
			updisp() ;
			break ;

		case IDC_C_MER:
			BodyList[MER] = IsDlgButtonChecked(hDlg, IDC_C_MER) ;
			updisp() ;
			break ;

		case IDC_C_VEN:
			BodyList[VEN] = IsDlgButtonChecked(hDlg, IDC_C_VEN) ;
			updisp() ;
			break ;

		case IDC_C_MAR:
			BodyList[MAR] = IsDlgButtonChecked(hDlg, IDC_C_MAR) ;
			updisp() ;
			break ;

		case IDC_C_JUP:
			BodyList[JUP] = IsDlgButtonChecked(hDlg, IDC_C_JUP) ;
			updisp() ;
			break ;

		case IDC_C_SAT:
			BodyList[SAT] = IsDlgButtonChecked(hDlg, IDC_C_SAT) ;
			updisp() ;
			break ;

		case IDC_C_URA:
			BodyList[URA] = IsDlgButtonChecked(hDlg, IDC_C_URA) ;
			 updisp() ;
			//IsRast() ;
			break ;

		case IDC_C_NEP:
			BodyList[NEP] = IsDlgButtonChecked(hDlg, IDC_C_NEP) ;
			 updisp() ;
			//IsRast() ;
			break ;

		case IDC_C_MOO:
			BodyList[MOO] = IsDlgButtonChecked(hDlg, IDC_C_MOO) ;
			 updisp() ;
			break ;

		case IDC_B_SLTP_ALL_BODIES:
			{
			int b, ID ;
			for (b = EAR ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case EAR: ID = IDC_C_SLTP_EAR  ; break ;
					case MOO: ID = IDC_C_SLTP_MOON ; break ;
					case SUN: ID = IDC_C_SLTP_SUN  ; break ;
					case MER: ID = IDC_C_SLTP_MER  ; break ;
					case VEN: ID = IDC_C_SLTP_VEN  ; break ;
					case MAR: ID = IDC_C_SLTP_MAR  ; break ;
					case JUP: ID = IDC_C_SLTP_JUP  ; break ;
					case SAT: ID = IDC_C_SLTP_SAT  ; break ;
					case URA: ID = IDC_C_SLTP_URA  ; break ;
					case NEP: ID = IDC_C_SLTP_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_CHECKED) ;
				ShowSysLineTP[b] = 1 ;
				VelsOn() ;
				}
			 updisp() ;
			}
			break ;

		case IDC_B_SLTP_NO_BODIES:
			{
			int b, ID ;
			for (b = EAR ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case EAR: ID = IDC_C_SLTP_EAR  ; break ;
					case MOO: ID = IDC_C_SLTP_MOON ; break ;
					case SUN: ID = IDC_C_SLTP_SUN  ; break ;
					case MER: ID = IDC_C_SLTP_MER  ; break ;
					case VEN: ID = IDC_C_SLTP_VEN  ; break ;
					case MAR: ID = IDC_C_SLTP_MAR  ; break ;
					case JUP: ID = IDC_C_SLTP_JUP  ; break ;
					case SAT: ID = IDC_C_SLTP_SAT  ; break ;
					case URA: ID = IDC_C_SLTP_URA  ; break ;
					case NEP: ID = IDC_C_SLTP_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_UNCHECKED) ;
				ShowSysLineTP[b] = 0 ;
				VelsOff() ;
				}
			 updisp() ;
			}
			break ;


		case IDC_C_SLTP_SUN:
			ShowSysLineTP[SUN] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_SUN) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_EAR:
			ShowSysLineTP[EAR] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_EAR) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_MER:
			ShowSysLineTP[MER] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_MER) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_VEN:
			ShowSysLineTP[VEN] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_VEN) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_MAR:
			ShowSysLineTP[MAR] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_MAR) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_JUP:
			ShowSysLineTP[JUP] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_JUP) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_SAT:
			ShowSysLineTP[SAT] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_SAT) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_URA:
			ShowSysLineTP[URA] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_URA) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_NEP:
			ShowSysLineTP[NEP] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_NEP) ;
			 updisp() ;
			break ;

		case IDC_C_SLTP_MOON:
			ShowSysLineTP[MOO] = IsDlgButtonChecked(hDlg, IDC_C_SLTP_MOON) ;
			 updisp() ;
			break ;

		case IDC_B_VIEW_ALL_BODIES:
			{
			int b, ID ;
			for (b = EAR ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case EAR: ID = IDC_C_VIEW_EAR  ; break ;
					case MOO: ID = IDC_C_VIEW_MOON ; break ;
					case SUN: ID = IDC_C_VIEW_SUN  ; break ;
					case MER: ID = IDC_C_VIEW_MER  ; break ;
					case VEN: ID = IDC_C_VIEW_VEN  ; break ;
					case MAR: ID = IDC_C_VIEW_MAR  ; break ;
					case JUP: ID = IDC_C_VIEW_JUP  ; break ;
					case SAT: ID = IDC_C_VIEW_SAT  ; break ;
					case URA: ID = IDC_C_VIEW_URA  ; break ;
					case NEP: ID = IDC_C_VIEW_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_CHECKED) ;
				ViewBody[b] = 1 ;
				}
			 updisp() ;
			}
			break ;

		case IDC_B_VIEW_NO_BODIES:
			{
			int b, ID ;
			for (b = EAR ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case EAR: ID = IDC_C_VIEW_EAR  ; break ;
					case MOO: ID = IDC_C_VIEW_MOON ; break ;
					case SUN: ID = IDC_C_VIEW_SUN  ; break ;
					case MER: ID = IDC_C_VIEW_MER  ; break ;
					case VEN: ID = IDC_C_VIEW_VEN  ; break ;
					case MAR: ID = IDC_C_VIEW_MAR  ; break ;
					case JUP: ID = IDC_C_VIEW_JUP  ; break ;
					case SAT: ID = IDC_C_VIEW_SAT  ; break ;
					case URA: ID = IDC_C_VIEW_URA  ; break ;
					case NEP: ID = IDC_C_VIEW_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_UNCHECKED) ;
				ViewBody[b] = 0 ;
				}
			 updisp() ;
			}
			break ;


		case IDC_C_VIEW_SUN:
			ViewBody[SUN] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_SUN) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_EAR:
			ViewBody[EAR] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_EAR) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_MER:
			ViewBody[MER] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_MER) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_VEN:
			ViewBody[VEN] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_VEN) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_MAR:
			ViewBody[MAR] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_MAR) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_JUP:
			ViewBody[JUP] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_JUP) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_SAT:
			ViewBody[SAT] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_SAT) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_URA:
			ViewBody[URA] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_URA) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_NEP:
			ViewBody[NEP] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_NEP) ;
			 updisp() ;
			break ;

		case IDC_C_VIEW_MOON:
			ViewBody[MOO] = IsDlgButtonChecked(hDlg, IDC_C_VIEW_MOON) ;
			 updisp() ;
			break ;

		case IDC_B_IB_ALL_BODIES:
			{
			int b, ID ;
			for (b = EAR ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case EAR: ID = IDC_C_IB_EAR  ; break ;
					case MOO: ID = IDC_C_IB_MOON ; break ;
					case SUN: ID = IDC_C_IB_SUN  ; break ;
					case MER: ID = IDC_C_IB_MER  ; break ;
					case VEN: ID = IDC_C_IB_VEN  ; break ;
					case MAR: ID = IDC_C_IB_MAR  ; break ;
					case JUP: ID = IDC_C_IB_JUP  ; break ;
					case SAT: ID = IDC_C_IB_SAT  ; break ;
					case URA: ID = IDC_C_IB_URA  ; break ;
					case NEP: ID = IDC_C_IB_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_CHECKED) ;
				ShowInterBodyTP[b] = 1 ;
				}
			 updisp() ;
			}
			break ;

		case IDC_B_IB_NO_BODIES:
			{
			int b, ID ;
			for (b = EAR ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case EAR: ID = IDC_C_IB_EAR  ; break ;
					case MOO: ID = IDC_C_IB_MOON ; break ;
					case SUN: ID = IDC_C_IB_SUN  ; break ;
					case MER: ID = IDC_C_IB_MER  ; break ;
					case VEN: ID = IDC_C_IB_VEN  ; break ;
					case MAR: ID = IDC_C_IB_MAR  ; break ;
					case JUP: ID = IDC_C_IB_JUP  ; break ;
					case SAT: ID = IDC_C_IB_SAT  ; break ;
					case URA: ID = IDC_C_IB_URA  ; break ;
					case NEP: ID = IDC_C_IB_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_UNCHECKED) ;
				ShowInterBodyTP[b] = 0 ;
				}
			 updisp() ;
			}
			break ;


		case IDC_C_IB_SUN:
			ShowInterBodyTP[SUN] = IsDlgButtonChecked(hDlg, IDC_C_IB_SUN) ;
			 updisp() ;
			break ;

		case IDC_C_IB_EAR:
			ShowInterBodyTP[EAR] = IsDlgButtonChecked(hDlg, IDC_C_IB_EAR) ;
			 updisp() ;
			break ;

		case IDC_C_IB_MER:
			ShowInterBodyTP[MER] = IsDlgButtonChecked(hDlg, IDC_C_IB_MER) ;
			 updisp() ;
			break ;

		case IDC_C_IB_VEN:
			ShowInterBodyTP[VEN] = IsDlgButtonChecked(hDlg, IDC_C_IB_VEN) ;
			 updisp() ;
			break ;

		case IDC_C_IB_MAR:
			ShowInterBodyTP[MAR] = IsDlgButtonChecked(hDlg, IDC_C_IB_MAR) ;
			 updisp() ;
			break ;

		case IDC_C_IB_JUP:
			ShowInterBodyTP[JUP] = IsDlgButtonChecked(hDlg, IDC_C_IB_JUP) ;
			 updisp() ;
			break ;

		case IDC_C_IB_SAT:
			ShowInterBodyTP[SAT] = IsDlgButtonChecked(hDlg, IDC_C_IB_SAT) ;
			 updisp() ;
			break ;

		case IDC_C_IB_URA:
			ShowInterBodyTP[URA] = IsDlgButtonChecked(hDlg, IDC_C_IB_URA) ;
			 updisp() ;
			break ;

		case IDC_C_IB_NEP:
			ShowInterBodyTP[NEP] = IsDlgButtonChecked(hDlg, IDC_C_IB_NEP) ;
			 updisp() ;
			break ;

		case IDC_C_IB_MOON:
			ShowInterBodyTP[MOO] = IsDlgButtonChecked(hDlg, IDC_C_IB_MOON) ;
			 updisp() ;
			break ;

		default:
			break ;
		}

	default:
		break ;
	}
  return FALSE ;
}

void ComposeEp( void )
// provide epoch pair from year, month, day,
// hour, minute and second for each pair
{
	double eptmp ;

			eptmp = ep ;
		// 1st epoch to nearest day
			  day = aE.aDay1 ;
			   mo = aE.aMon1 ;
			   yr = aE.aYr1 ;
			   setepoch() ;
		// add in fraction of day
		   AstEp1 = aE.aEp1 = ep + (aE.aHr1 + aE.aMn1/60.0 + aE.aSc1/3600.0) / 24.0 ;

		// 2nd epoch to nearest day
			  day = aE.aDay2 ;
			   mo = aE.aMon2 ;
			   yr = aE.aYr2 ;
			   setepoch() ;
		// add in fraction of day
		   AstEp2 = aE.aEp2 = ep + (aE.aHr2 + aE.aMn2/60.0 + aE.aSc2/3600.0) / 24.0 ;

		// astron grand period
		   AstGP  = AstEp2 - AstEp1 ;
			   ep = eptmp ;

		// update display etc ;
			if (dont_wait)
				updisp() ;
}

BOOL CALLBACK TabEpochsDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{

 static HWND hW ;

 // these relate to the bud series
 static HWND E_D1, E_D2 ;
 static HWND E_M1, E_M2 ;
 static HWND E_Y1, E_Y2 ;
 static HWND E_H1, E_MN1, E_S1 ;
 static HWND E_H2, E_MN2, E_S2 ;

 // these relate to general dates
 static HWND E_ASTD1, U_ASTD1, E_ASTD2, U_ASTD2 ;
 static HWND E_ASTM1, U_ASTM1, E_ASTM2, U_ASTM2 ;
 static HWND E_ASTY1, U_ASTY1, E_ASTY2, U_ASTY2 ;
 static HWND E_ASTH1, U_ASTH1, E_ASTMN1, U_ASTMN1, E_ASTS1, U_ASTS1 ;
 static HWND E_ASTH2, U_ASTH2, E_ASTMN2, U_ASTMN2, E_ASTS2, U_ASTS2 ;

		   BOOL F = FALSE, T = TRUE ;
		    int i ;

	switch(msg)
	{
	case WM_INITDIALOG:

		  E_D1 = GetDlgItem(hDlg, IDC_E_D1) ;
		  E_M1 = GetDlgItem(hDlg, IDC_E_M1) ;
		  E_Y1 = GetDlgItem(hDlg, IDC_E_Y1) ;
		  E_D2 = GetDlgItem(hDlg, IDC_E_D2) ;
		  E_M2 = GetDlgItem(hDlg, IDC_E_M2) ;
		  E_Y2 = GetDlgItem(hDlg, IDC_E_Y2) ;

		  E_S1  = GetDlgItem(hDlg, IDC_E_SEC1) ;
		  E_MN1 = GetDlgItem(hDlg, IDC_E_MIN1) ;
		  E_H1  = GetDlgItem(hDlg, IDC_E_HR1) ;
		  E_S2  = GetDlgItem(hDlg, IDC_E_SEC2) ;
		  E_MN2 = GetDlgItem(hDlg, IDC_E_MIN2) ;
		  E_H2  = GetDlgItem(hDlg, IDC_E_HR2) ;

		  E_ASTD1 = GetDlgItem(hDlg, IDC_E_ASTD1) ;
		  U_ASTD1 = GetDlgItem(hDlg, IDC_U_ASTD1) ;

		  E_ASTM1 = GetDlgItem(hDlg, IDC_E_ASTM1) ;
		  U_ASTM1 = GetDlgItem(hDlg, IDC_U_ASTM1) ;

		  E_ASTY1 = GetDlgItem(hDlg, IDC_E_ASTY1) ;
		  U_ASTY1 = GetDlgItem(hDlg, IDC_U_ASTY1) ;

		  E_ASTD2 = GetDlgItem(hDlg, IDC_E_ASTD2) ;
		  U_ASTD2 = GetDlgItem(hDlg, IDC_U_ASTD2) ;

		  E_ASTM2 = GetDlgItem(hDlg, IDC_E_ASTM2) ;
		  U_ASTM2 = GetDlgItem(hDlg, IDC_U_ASTM2) ;

		  E_ASTY2 = GetDlgItem(hDlg, IDC_E_ASTY2) ;
		  U_ASTY2 = GetDlgItem(hDlg, IDC_U_ASTY2) ;

		  E_ASTS1  = GetDlgItem(hDlg, IDC_E_ASTSEC1) ;
		  U_ASTS1  = GetDlgItem(hDlg, IDC_U_ASTSEC1) ;
		  E_ASTMN1 = GetDlgItem(hDlg, IDC_E_ASTMIN1) ;
		  U_ASTMN1 = GetDlgItem(hDlg, IDC_U_ASTMIN1) ;
		  E_ASTH1  = GetDlgItem(hDlg, IDC_E_ASTHR1) ;
		  U_ASTH1  = GetDlgItem(hDlg, IDC_U_ASTHR1) ;
		  E_ASTS2  = GetDlgItem(hDlg, IDC_E_ASTSEC2) ;
		  U_ASTS2  = GetDlgItem(hDlg, IDC_U_ASTSEC2) ;
		  E_ASTMN2 = GetDlgItem(hDlg, IDC_E_ASTMIN2) ;
		  U_ASTMN2 = GetDlgItem(hDlg, IDC_U_ASTMIN2) ;
		  E_ASTH2  = GetDlgItem(hDlg, IDC_E_ASTHR2) ;
		  U_ASTH2  = GetDlgItem(hDlg, IDC_U_ASTHR2) ;

	      SetUDRng(U_ASTD1,  31, 1) ;
	      SetUDRng(U_ASTM1,  12, 1) ;
	      SetUDRng(U_ASTY1,  2100, 1900) ;

	      SetUDRng(U_ASTS1,  59, 0) ;
	      SetUDRng(U_ASTMN1, 59, 0) ;
	      SetUDRng(U_ASTH1,  23, 0) ;

	      SetUDRng(U_ASTD2,  31, 1) ;
	      SetUDRng(U_ASTM2,  12, 1) ;
	      SetUDRng(U_ASTY2,  2100, 1900) ;

	      SetUDRng(U_ASTS2,  59, 0) ;
	      SetUDRng(U_ASTMN2, 59, 0) ;
	      SetUDRng(U_ASTH2,  23, 0) ;


	// No epochs yet
			for (
				             i = 0,
				   st.AllEpSet = 0,
				     st.Ep1Set = 0,
				     st.Ep2Set = 0 ;
				   i < 12 ; 
				   st.Set[i++] = 0
				) ;

	//EnableWindow(hBuild, F) ;

	// No data yet, disallow Fourier settings
	EnableWindow(GetDlgItem(hDlgFourier,IDC_E_LORD), F) ;
	EnableWindow(GetDlgItem(hDlgFourier,IDC_U_LORD), F) ;
	EnableWindow(GetDlgItem(hDlgFourier,IDC_E_HORD), F) ;
	EnableWindow(GetDlgItem(hDlgFourier,IDC_U_HORD), F) ;

	EnableWindow(GetDlgItem(hDlgFourier,IDC_E_ASTLORD), F) ;
	EnableWindow(GetDlgItem(hDlgFourier,IDC_U_ASTLORD), F) ;
	EnableWindow(GetDlgItem(hDlgFourier,IDC_E_ASTHORD), F) ;
	EnableWindow(GetDlgItem(hDlgFourier,IDC_U_ASTHORD), F) ;

	EnableWindow(GetDlgItem(hDlgSpectra,IDC_C_ORDLINES),  F) ;
	EnableWindow(GetDlgItem(hDlg, IDC_B_ON_CLICK), dont_wait ? F : T) ;
	CheckDlgButton(hDlg, IDC_C_WAIT_FOR_OK, dont_wait ? BST_UNCHECKED : BST_CHECKED) ;

	OnChildDialogInit(hDlg) ;

		return TRUE ;


 	   case WM_VSCROLL:  // Service up/down controls
// Since all u/d ctrls here are auto-buddy integer style,
// they are serviced automatically. No code is needed
// here just now.
		   hW = (HWND)lParam ;
		   break ;

	case WM_TIMER:
		switch (wParam)
		{
		default:	break ;
		}
		break ;

	case WM_COMMAND:

		switch(HIWORD(wParam)) // notifications
		{
		BOOL err ;
		case EN_CHANGE: // an edit box has been edited

			switch(LOWORD(wParam)) // which one?
			{
		case IDC_E_ASTD1:	// day of month 1
			aE.aDay1 = GetDlgItemInt(hDlg, IDC_E_ASTD1, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTM1:	// month of year 1
			aE.aMon1 = GetDlgItemInt(hDlg, IDC_E_ASTM1, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTY1:	// year 1
			aE.aYr1 = GetDlgItemInt(hDlg, IDC_E_ASTY1, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTHR1:	// hour of day 1
			aE.aHr1 = GetDlgItemInt(hDlg, IDC_E_ASTHR1, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTMIN1:	// minute of hour 1
			aE.aMn1 = GetDlgItemInt(hDlg, IDC_E_ASTMIN1, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTSEC1: // second of minute 1
			aE.aSc1 = GetDlgItemInt(hDlg, IDC_E_ASTSEC1, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTD2:
			aE.aDay2 = GetDlgItemInt(hDlg, IDC_E_ASTD2, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTM2:
			aE.aMon2 = GetDlgItemInt(hDlg, IDC_E_ASTM2, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTY2:
			aE.aYr2 = GetDlgItemInt(hDlg, IDC_E_ASTY2, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTHR2:
			aE.aHr2 = GetDlgItemInt(hDlg, IDC_E_ASTHR2, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTMIN2:
			aE.aMn2 = GetDlgItemInt(hDlg, IDC_E_ASTMIN2, &err, FALSE) ;
			ComposeEp() ;
			break ;

		case IDC_E_ASTSEC2:
			aE.aSc2 = GetDlgItemInt(hDlg, IDC_E_ASTSEC2, &err, FALSE) ;
			ComposeEp() ;
			break ;

			default:
				break ;
			} // switch (LOWORD(wParam))

			break ; // case EN_CHANGE

		default:
			break ;
		} // switch (HIWORD(wParam))


		switch(LOWORD(wParam))
		{ 
		// treat the new epochs as bud date bounds, find alignments, spectra etc
		case IDC_B_APPLY_BOUND:

		for ( i = 0,
			  st.Ep1Set = st.Ep2Set = st.AllEpSet = 1 ;
		      i < 12 ; st.Set[i++] = 1 ) ;
		allowbuild = 1 ; // immediate
		SendMessage( hDlgSource, WM_COMMAND, TOTAL_REBUILD, 0L) ;

			break ;

		case IDC_C_WAIT_FOR_OK:

			dont_wait = !IsDlgButtonChecked(hDlg, IDC_C_WAIT_FOR_OK) ;
			EnableWindow(GetDlgItem(hDlg, IDC_B_ON_CLICK), dont_wait ? F : T) ;

			break ;

		case IDC_B_ON_CLICK:

		Refresh() ;
		// go get what's needed
		SendMessage(hDlgSource, WM_COMMAND, TG_GET_ALIGNS, 0L) ;
		updisp();

			break ;

		case IDC_B_MATCH_TO_BUD_SERIES:

		SetDlgItemText(hDlg,IDC_E_ASTD1,   BudSearch->szBudDay1) ;
		SetDlgItemText(hDlg,IDC_E_ASTM1,   BudSearch->szBudMon1) ;
		SetDlgItemText(hDlg,IDC_E_ASTY1,   BudSearch->szBudYr1 ) ;
		SetDlgItemText(hDlg,IDC_E_ASTHR1,  BudSearch->szBudHr1 ) ;
		SetDlgItemText(hDlg,IDC_E_ASTMIN1, BudSearch->szBudMn1 ) ;
		SetDlgItemText(hDlg,IDC_E_ASTSEC1, BudSearch->szBudSc1 ) ;

		SetDlgItemText(hDlg,IDC_E_ASTD2,   BudSearch->szBudDay2) ;
		SetDlgItemText(hDlg,IDC_E_ASTM2,   BudSearch->szBudMon2) ;
		SetDlgItemText(hDlg,IDC_E_ASTY2,   BudSearch->szBudYr2 ) ;
		SetDlgItemText(hDlg,IDC_E_ASTHR2,  BudSearch->szBudHr2 ) ;
		SetDlgItemText(hDlg,IDC_E_ASTMIN2, BudSearch->szBudMn2 ) ;
		SetDlgItemText(hDlg,IDC_E_ASTSEC2, BudSearch->szBudSc2 ) ;
		AlignResolution = 0.02 ;
		checkeps() ;
			break ;

		case IDC_B_USE_DEF_EPOS:

		SetDlgItemText(hDlg,IDC_E_ASTD1,   "01") ;
		SetDlgItemText(hDlg,IDC_E_ASTM1,   "01") ;
		SetDlgItemText(hDlg,IDC_E_ASTY1,   "1983" ) ;
		SetDlgItemText(hDlg,IDC_E_ASTHR1,  "12" ) ;
		SetDlgItemText(hDlg,IDC_E_ASTMIN1, "00" ) ;
		SetDlgItemText(hDlg,IDC_E_ASTSEC1, "00" ) ;

		SetDlgItemText(hDlg,IDC_E_ASTD2,   "01") ;
		SetDlgItemText(hDlg,IDC_E_ASTM2,   "01") ;
		SetDlgItemText(hDlg,IDC_E_ASTY2,   "2000" ) ;
		SetDlgItemText(hDlg,IDC_E_ASTHR2,  "00" ) ;
		SetDlgItemText(hDlg,IDC_E_ASTMIN2, "00" ) ;
		SetDlgItemText(hDlg,IDC_E_ASTSEC2, "00" ) ;
		AlignResolution = 0.02 ;
		checkeps() ;
			break ;
		default:
			break ;
		}

	default:
		break ;
	}
  return FALSE ;

}

BOOL CALLBACK TabMiscDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam ) // Contains the Raster routines now
{

	switch(msg)
	{
	case WM_INITDIALOG:

	OnChildDialogInit(hDlg) ;
		return TRUE ;

 	   case WM_VSCROLL:  // Service up/down controls
// Since all u/d ctrls here are auto-buddy integer style,
// they are serviced automatically. No code is needed
// here just now.
		   break ;

	case WM_TIMER:
		switch (wParam)
		{
		default:	break ;
		}
		break ;

	case WM_COMMAND:

		switch(LOWORD(wParam))
		{
	// Select/Deselect into "Raster"
		case IDC_C_RAST_SUN:
			RastBodyList[SUN] = IsDlgButtonChecked(hDlg, IDC_C_RAST_SUN) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			break ;

		case IDC_C_RAST_MER:
			RastBodyList[MER] = IsDlgButtonChecked(hDlg, IDC_C_RAST_MER) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			break ;

		case IDC_C_RAST_VEN:
			RastBodyList[VEN] = IsDlgButtonChecked(hDlg, IDC_C_RAST_VEN) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			break ;

		case IDC_C_RAST_MAR:
			RastBodyList[MAR] = IsDlgButtonChecked(hDlg, IDC_C_RAST_MAR) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			break ;

		case IDC_C_RAST_JUP:
			RastBodyList[JUP] = IsDlgButtonChecked(hDlg, IDC_C_RAST_JUP) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			 updisp() ;
			break ;

		case IDC_C_RAST_SAT:
			RastBodyList[SAT] = IsDlgButtonChecked(hDlg, IDC_C_RAST_SAT) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			 updisp() ;
			break ;

		case IDC_C_RAST_URA:
			RastBodyList[URA] = IsDlgButtonChecked(hDlg, IDC_C_RAST_URA) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			 updisp() ;
			break ;

		case IDC_C_RAST_NEP:
			RastBodyList[NEP] = IsDlgButtonChecked(hDlg, IDC_C_RAST_NEP) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			 updisp() ;
			break ;

		case IDC_B_RAST_ENTER:  // accept
			updisp() ;
			break ;

		case IDC_B_RAST_ALL_BODIES:
			{
			int b, ID ;
			for (b = MER ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case SUN: ID = IDC_C_RAST_SUN  ; break ;
					case MER: ID = IDC_C_RAST_MER  ; break ;
					case VEN: ID = IDC_C_RAST_VEN  ; break ;
					case MAR: ID = IDC_C_RAST_MAR  ; break ;
					case JUP: ID = IDC_C_RAST_JUP  ; break ;
					case SAT: ID = IDC_C_RAST_SAT  ; break ;
					case URA: ID = IDC_C_RAST_URA  ; break ;
					case NEP: ID = IDC_C_RAST_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_CHECKED) ;
				RastBodyList[b] = 1 ;
				}
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			IsRast() ;
			}
			break ;

		case IDC_B_RAST_NO_BODIES:
			{
			int b, ID ;
			for (b = MER ; b <= SUN ; b++)
				{
				if (b == PLU) continue ;
				switch(b)
					{
					case SUN: ID = IDC_C_RAST_SUN  ; break ;
					case MER: ID = IDC_C_RAST_MER  ; break ;
					case VEN: ID = IDC_C_RAST_VEN  ; break ;
					case MAR: ID = IDC_C_RAST_MAR  ; break ;
					case JUP: ID = IDC_C_RAST_JUP  ; break ;
					case SAT: ID = IDC_C_RAST_SAT  ; break ;
					case URA: ID = IDC_C_RAST_URA  ; break ;
					case NEP: ID = IDC_C_RAST_NEP  ; break ;
					}
				CheckDlgButton(hDlg, ID, BST_UNCHECKED) ;
				RastBodyList[b] = 0 ;
				}
			IsRast() ;
			SendMessage(hDlg, WM_COMMAND, IDC_C_ALL_ALS, 0L) ;
			EnableWindow(GetDlgItem(hDlg, IDC_C_ALL_ALS), CheckRastBodyList()) ;
			 updisp() ;
			}
			break ;

		case IDC_C_ALL_ALS:
			{
			BOOL B ;
			PlotAllAls = IsDlgButtonChecked(hDlg, IDC_C_ALL_ALS) ;
					 B = PlotAllAls ? TRUE : FALSE ;

				EnableWindow(GetDlgItem(hDlg, IDC_C_PGRASTER),		 B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_LINK_LUNAX),	 B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_WANT_ICONS),	 B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_WANT_JOINS),	 B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_AXEPOCH_LABELS), B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DAYTICK_LABELS), B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_PEAKDIP_POPUP),  B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ALIGN_POPUP),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ALS_XREF),       B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_PEAKDIP_XREF),   B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_S_POPUPPANEL),     B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_S_RASTPANEL),      B) ;

			if (!PlotAllAls)
			{
				CheckDlgButton(hDlg, IDC_C_PGRASTER, BST_UNCHECKED) ;
				SendMessage(hDlg, WM_COMMAND, IDC_C_PGRASTER, 0L) ;
			}

			}
			break ;

		case IDC_C_PGRASTER:
			{
				 static RECT drc, arc, rst ;
				       POINT pt ;

			if (IsDlgButtonChecked(hDlg, IDC_C_PGRASTER))
			{
				// if Rasterised Dip/Peak Dialog box does not yet exist
				// create and show it now
				if (hRastDlg == (HWND)NULL)
				{

					hRastDlg = CreateDialog
						(
			            hInst,
			            MAKEINTRESOURCE(IDD_RAST_DIP),
			            NULL,
			            RasterisedDipsDlgProc
						) ;
				}

				GetWindowRect(hPanelDlg,  &drc) ; // the control panel rectangle
				GetWindowRect(hRastDlg, &rst) ; // dip/peak dlg box  rectangle

			// Get and convert the current Archive Window Rect
			// to client co-ordinates
				GetWindowRect(hWndArch, &arc) ;
				pt.x = arc.left ;
				pt.y = arc.top ;
				ScreenToClient(hWndCtrl, &pt) ;
				arc.left = pt.x ;
				arc.top  = pt.y ;
				pt.x = arc.right ;
				pt.y = arc.bottom ;
				ScreenToClient(hWndCtrl, &pt) ;
				arc.right  = pt.x ;
				arc.bottom = pt.y ;

			// The dialog box calling for this must be showing.
			// Move it to the top left.
				SetWindowPos(hPanelDlg, HWND_TOP,
								0,0,0,0,
								SWP_NOSIZE) ;

			// Move the dip/peak dlg box above the raster
				SetWindowPos(hRastDlg, HWND_TOPMOST,
							 rcctrl.left + (drc.right - drc.left),
							 rcctrl.top,
							 rst.right - rst.left,
							 rst.bottom - rst.top,
							 SWP_SHOWWINDOW) ;

			// Move the Raster Window to the right of the Dialog Box.
				SetWindowPos(hWndRast, HWND_TOP,
					         rcctrl.left + (drc.right - drc.left),	// new x
							 rst.bottom - rst.top,					// new y
							(rcctrl.right - rcctrl.left) - (drc.right - drc.left),	// new width
							(rcctrl.bottom - rcctrl.top) - (rst.bottom - rst.top),	// new height
							 SWP_SHOWWINDOW) ;


			// Move the Archive chart to the left of the Raster
				SetWindowPos(hWndArch, HWND_TOP,
					arc.left,				// same x as old
					arc.top,				// same y as old
					drc.right - drc.left,	// same width as the Dialog Box
					arc.bottom - arc.top,	// same height as old
					SWP_SHOWWINDOW) ;

					PlotRaster = 1 ;
			}
			else // Hide the Raster, and restore the Archive chart
			{
				ShowWindow(hRastDlg, SW_HIDE) ; // hide the Dip/Peak dialog first
				ShowWindow(hWndRast, SW_HIDE) ;

				SetWindowPos(hWndArch, HWND_TOP,
					arc.left,
					arc.top,
					arc.right - arc.left,
					arc.bottom - arc.top,
					SWP_SHOWWINDOW) ;

					PlotRaster = 0 ;
			}
			}
			break ;

		case IDC_C_DAYTICK_LABELS:
			wantDayLabels = IsDlgButtonChecked(hDlg, IDC_C_DAYTICK_LABELS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_AXEPOCH_LABELS:
			wantAxialLabels = IsDlgButtonChecked(hDlg, IDC_C_AXEPOCH_LABELS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_PEAKDIP_XREF:
			wantXref = IsDlgButtonChecked(hDlg, IDC_C_PEAKDIP_XREF) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_ALS_XREF:
			wantAlsXref = IsDlgButtonChecked(hDlg, IDC_C_ALS_XREF) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_PEAKDIP_POPUP:
			wantPDPopups = IsDlgButtonChecked(hDlg, IDC_C_PEAKDIP_POPUP) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_ALIGN_POPUP:
			wantAlPopups = IsDlgButtonChecked(hDlg, IDC_C_ALIGN_POPUP) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_WANT_ICONS:
			wantIcons = IsDlgButtonChecked(hDlg, IDC_C_WANT_ICONS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_WANT_JOINS:
			wantJoins = IsDlgButtonChecked(hDlg, IDC_C_WANT_JOINS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_LINK_LUNAX:
			wantLunAxials = IsDlgButtonChecked(hDlg, IDC_C_LINK_LUNAX) ;
			 updisp() ;
			break ;

	 // geocentric longitude or RA of the ecliptic lunar nodal
		case IDC_C_INODAL: 
			PlotNEcLo = BodyList[NOD] = IsDlgButtonChecked(hDlg, IDC_C_INODAL) ;
			 updisp() ;
			break ;

	 // geocentric longitude or RA of the equatorial lunar nodal
		case IDC_C_EQN:	  
			PlotNEqLo = BodyList[EQN] = IsDlgButtonChecked(hDlg, IDC_C_EQN) ;
			 updisp() ;
			break ;

		case IDC_C_PERI:	// geocentric longitude or RA of the perigee
			PlotPeriLo = BodyList[PER] = IsDlgButtonChecked(hDlg, IDC_C_PERI) ;
			 updisp() ;
			break ;

	 // Direction of Systemic motion
		case IDC_C_MOT:  
			PlotMot = BodyList[MOT] = IsDlgButtonChecked(hDlg, IDC_C_MOT) ;

		 // if MOT is asserted, make sure VELS is, too. 
			if (PlotMot) VelsOn() ;
			 updisp() ;
			break ;

	 // Alignment of Systemic motion
		case IDC_C_AMOT:  
			PlotAMot = BodyList[MOT] = IsDlgButtonChecked(hDlg, IDC_C_AMOT) ;

		 // if AMOT is asserted, make sure VELS is, too. 
			if (PlotAMot) VelsOn() ;
			 updisp() ;
			break ;

		case IDC_R_HELIOC_MOTS:  
			wantHeliocMots = IsDlgButtonChecked(hDlg, IDC_R_HELIOC_MOTS) ;
			if (PlotMot || PlotAMot)
			 updisp() ;
			break ;

		case IDC_R_GEOC_MOTS:  
			wantHeliocMots = !IsDlgButtonChecked(hDlg, IDC_R_GEOC_MOTS) ;
			if (PlotMot || PlotAMot)
			 updisp() ;
			break ;

		default:
			break ;
		}
	default:
		break ;
	}
  return FALSE ;
}

BOOL CALLBACK TabDisplayDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
  static HWND hW, W1, W2 ;
  static HWND E_MS, U_MS ;
  static HWND E_PDB, U_PDB ;
  static HWND E_PDA, U_PDA ;
  static char szbelow[30], szabove[30] ;
  static double oldLoPer, oldHiPer ;

		 BOOL snafu ;
	   static TempVal, tSpan, hold = 1000, sdhold = 1000 ;
	   static char buff[255] ;

	switch (msg)
	{
	case WM_TIMER:
		switch(wParam)
		{
		case IDT_MSPAN:
			  KillTimer(hDlg, IDT_MSPAN) ;
			SendMessage(hDlg, WM_COMMAND, TG_MSPAN, 0L) ;
			break ;

			break ;
		}
			break ;

	case WM_INITDIALOG:

		  W1 = GetDlgItem(hDlg, IDC_C_RSHF) ;
		  W2 = GetDlgItem(hDlg, IDC_C_MSHF) ;

		E_MS = GetDlgItem(hDlg, IDC_E_MSPAN) ;
		U_MS = GetDlgItem(hDlg, IDC_U_MSPAN) ;

	    SetUDRng(U_MS, 93, 3) ;
	    SetUDPos(U_MS, MeanSpan) ;

		E_PDB = GetDlgItem(hDlg, IDC_E_NOPERIODSBELOW) ; // omit periods Below some low period (hi order)
		U_PDB = GetDlgItem(hDlg, IDC_U_NOPERIODSBELOW) ;

	    SetUDRng(U_PDB, 10000, 0) ;
	    SetUDPos(U_PDB, (int)(100.0 * LoPer)) ;
		sprintf(szbelow, "%3.2f", LoPer) ;
		SetDlgItemText(hDlg, IDC_E_NOPERIODSBELOW, szbelow) ;

		E_PDA = GetDlgItem(hDlg, IDC_E_NOPERIODSABOVE) ; // omit periods Above some high period (lo order)
		U_PDA = GetDlgItem(hDlg, IDC_U_NOPERIODSABOVE) ;

	    SetUDRng(U_PDA, 10000, 0) ;
	    SetUDPos(U_PDA, (int)(100.0 * HiPer)) ;
		sprintf(szabove, "%3.2f", HiPer) ;
		SetDlgItemText(hDlg, IDC_E_NOPERIODSABOVE, szabove) ;

			if (PlotComp)
				EnableWindow(W1, TRUE) ;
			else
			{
					CheckDlgButton(hDlg, IDC_C_RSHF, 0) ;
					PlotShifts = 0 ;
					EnableWindow(W1, FALSE) ;
			}

			if (mPlotComp && wantMovingMean)
				EnableWindow(W2, TRUE) ;
			else
			{
					CheckDlgButton(hDlg, IDC_C_MSHF, 0) ;
					PlotShifts = 0 ;
					EnableWindow(W2, FALSE) ;
			}

	CheckRadioButton(hDlg,	IDC_R_VELDIR_MB,
							IDC_R_JUPDIR_MB,
							IDC_R_ACCDIR_MB) ;

	OnChildDialogInit(hDlg) ;
		return TRUE ;

 	   case WM_VSCROLL:  // Service up/down controls

		   hW = (HWND)lParam ;

			   if (hW == U_MS) // span of moving Lambda mean
		   {
				SendMessage
				   (
					E_MS,
					WM_GETTEXT,
					255,
				   (LPARAM)buff
				   ) ;

				TempVal = atoi(buff) ;
				// See if the span has changed.
				// If it has, force rebuild of
				// moving mean data.
				SendMessage(hDlg, WM_COMMAND, TG_MSPAN, 0L) ;
		   }
			   //break ;

			   if (hW == U_PDB) // omit high orders corresponding to periods below some low period. 
			   {
				   LoPer = (double)GetUDPos(U_PDB) / 100.0 ;
				   sprintf(szbelow, "%3.2f", LoPer) ;
				   SetDlgItemText(hDlg, IDC_E_NOPERIODSBELOW, szbelow ) ;
			   }
			   //break ;

			   if (hW == U_PDA) // omit low orders corresponding to periods above some high period
			   {
				   HiPer = (double)GetUDPos(U_PDA) / 100.0 ;
				   sprintf(szabove, "%3.2f", HiPer) ;
				   SetDlgItemText(hDlg, IDC_E_NOPERIODSABOVE, szabove ) ;
			   }
			   break ;

case WM_COMMAND:

		switch(LOWORD(wParam))
		{
		   case IDC_C_MOVINGMEAN2: // check state has changed.

		   if (wantMovingMean = IsDlgButtonChecked(hDlg,IDC_C_MOVINGMEAN2))
		   {
		   // We want moving means and the associated display options.
		   // First assume the moving mean data exist and
		   // enable the display option controls for means....
		   
			   EnableMnDspCtls( TRUE ) ;
               EnableWindow(E_MS, TRUE ) ; // enable the span edit box
               EnableWindow(U_MS, TRUE ) ; // and span UD ctl
               EnableWindow(GetDlgItem(hDlg,IDC_S_OF2), TRUE ) ; // text
		   
		   // .....BUT check whether they in fact exist. If they don't,
		   // try to get them, and if that works, leave the
		   // buttons enabled, else disable them.
			SendMessage(hDlg, WM_COMMAND, TG_MOVMEAN, 0L) ;
		   }
	 	   else // We don't want to use means, existing or not,
			    // so just disable the buttons.
		   {
			   EnableMnDspCtls( FALSE ) ;
               EnableWindow(E_MS, FALSE ) ; // disable edit box
               EnableWindow(U_MS, FALSE ) ; // and UD ctl
               EnableWindow(GetDlgItem(hDlg,IDC_S_OF2), FALSE) ; // static text
		   }
				break ;

		   case TG_MOVMEAN:
		  // if the raw data do not exist
		  if (!_is.DataExist)
		  {
			   EnableMnDspCtls( FALSE ) ;
               EnableWindow(E_MS, FALSE ) ; // disable edit box
               EnableWindow(U_MS, FALSE ) ; // and UD ctl
               EnableWindow(GetDlgItem(hDlg,IDC_S_OF2), FALSE) ; // static text
				msgbox = 1 ;
		        MessageBox( hDlg, 
					        "There are no raw data available\n" \
							"from which to form Moving Means.",
							"No Raw Data",
							MB_ICONEXCLAMATION|MB_OK) ;
				msgbox = 0 ;
		  }
		  else
		  // if the raw data do exist, but the means don't, go get them
		  if (!_is.MeansExist) 
		  {
			  int i ;

				  if (				 
					   RunningMean
						(
						 bud,
						 MeanSpan,
						 pFourier
						)
					 )
				  {
				  _is.MeansExist = 1 ; // it worked!
				  // but current Agraph(s), if any, now invalid
				  _is.rAgraphExists = _is.mAgraphExists = 0 ;
				  // OK, get highest and lowest
				  for ( i = 0,
					    pFourier->mHidata = -1.0e8,
					    pFourier->mLodata =  1.0e8 ;
				        i < bud ; i++ )
				  {
					  pFourier->mHidata =
						  (pFourier->mdata[i] > pFourier->mHidata)?
						  pFourier->mdata[i] : pFourier->mHidata ;
					  pFourier->mLodata =
						  (pFourier->mLodata > pFourier->mdata[i])?
						  pFourier->mdata[i] : pFourier->mLodata ;
				  }
				  // Obtain the corresponding Fourier component
			      analysis(pFourier, bud, mstash, st.pord, 0) ;
				  
		          ivrc(hWndArch,NULL,TRUE) ;
		          //UpdateWindow(hWndArch) ;
				  }
				  else // means not available for some other reason
				  {
					  _is.MeansExist = 0 ;

			     EnableMnDspCtls( FALSE ) ;
                 EnableWindow(E_MS, FALSE ) ; // disable edit box
                 EnableWindow(U_MS, FALSE ) ; // and UD ctl
                 EnableWindow(GetDlgItem(hDlg,IDC_S_OF2), FALSE) ; // text
/*
					msgbox = 1 ;
MessageBox( hDlg,
"Error: The Moving Mean " \
"data set could not be created.",
"Moving Means",
MB_ICONEXCLAMATION|MB_OK ) ;
					msgbox = 0 ;
*/
				  }
		  } 
			   break ;

		case IDC_C_RDAT:

			// Display the raw lambda data over the
			// currently defined grand period.

			PlotData = IsDlgButtonChecked(hDlg, IDC_C_RDAT) ;
			 updisp() ;
			break ;


		case IDC_C_RSYN:

			// Standard synthesis of raw lambda data, using the
			// currently defined order limits, over the currently
			// defined grand period.

			PlotSynth = IsDlgButtonChecked(hDlg, IDC_C_RSYN) ;

			if (PlotSynth)
			{
               if (!_is.LamSpExists)
			   {
				   pSamp->Peaks = 0 ;
				   SetWindowText(hWndFetch,"Raw Lam. Spec") ;
				_is.LamSpExists = GetLambdaSpectrum( RAW ) ;
				   SetWindowText(hWndFetch,"") ;
			   }

			   if (!_is.LamSnExists)
			   {
				wantBumps = 1 ; wantOneDay = 0 ;
				   SetWindowText(hWndFetch,"Raw Lam. Synth") ;
				_is.LamSnExists = GetLambdaSynthesis( RAW, 0 ) ;
				   SetWindowText(hWndFetch,"") ;
			   }
			}
			updisp() ;
			break ;

		case IDC_C_RAWDIPS:
			PlotRawDips = IsDlgButtonChecked(hDlg, IDC_C_RAWDIPS) ;
//			if (PlotRawDips)
//				PlotSynthRawDips() ;
//			else
				updisp() ;
			break ;
			
		case IDC_C_RAWTUNEDDIPS:
			PlotRawTunedDips = IsDlgButtonChecked(hDlg, IDC_C_RAWTUNEDDIPS) ;
			 updisp() ;
			break ;

		case IDC_C_RAWPEAKS:
			PlotRawPeaks = IsDlgButtonChecked(hDlg, IDC_C_RAWPEAKS) ;
			 updisp() ;
			break ;
			
		case IDC_C_RAWTUNEDPEAKS:
			PlotRawTunedPeaks = IsDlgButtonChecked(hDlg, IDC_C_RAWTUNEDPEAKS) ;
			 updisp() ;
			break ;

		case IDC_C_RFSYNTH:	 // Forced synthesis of Raw lambdas

			// The amplitudes of the components are forced to a
			// common, constant value. Only the phase distribution of
			// the components reflects in the synthesis.

			PlotFSynth = IsDlgButtonChecked(hDlg, IDC_C_RFSYNTH) ;
			if (PlotFSynth)
			{
               if (!_is.LamSpExists)
			   {
				   pSamp->Peaks = 0 ;
				   SetWindowText(hWndFetch,"Raw Lam. Spect.") ;
				_is.LamSpExists = GetLambdaSpectrum( RAW ) ;
				   SetWindowText(hWndFetch,"") ;
			   }
			   if (!_is.LamFSnExists)
			   {
				   SetWindowText(hWndFetch,"Forced Synth.") ;
				_is.LamFSnExists = GetLambdaSynthesis( RAW, 1 ) ;
				   SetWindowText(hWndFetch,"") ;
			   }
			}
			updisp() ;
			break ;

		case IDC_C_EXCLUDEPERIODS:
			ExclPers = IsDlgButtonChecked(hDlg, IDC_C_EXCLUDEPERIODS) ;
			EnableWindow(GetDlgItem(hDlg, IDC_E_NOPERIODSBELOW), ExclPers) ;
			EnableWindow(GetDlgItem(hDlg, IDC_E_NOPERIODSABOVE), ExclPers) ;

			if (ExclPers)
			{
				FilterLP = FilterHP = 1 ;
				sprintf(szbelow,"%3.2f", LoPer) ;
				SetDlgItemText(hDlg, IDC_E_NOPERIODSBELOW, szbelow) ;
				sprintf(szabove,"%3.2f", HiPer) ;
				SetDlgItemText(hDlg, IDC_E_NOPERIODSABOVE, szabove) ;
			}
			else
				FilterLP = FilterHP = 0 ;

			// we have a change of top and bottom orders

			Refresh() ;
			SendMessage(hDlgSource, WM_COMMAND, TG_GET_ALIGNS, 0L) ;
			if (PlotSynth || mPlotSynth) updisp() ;
			break ;

		case IDC_E_NOPERIODSBELOW:
			oldLoPer = LoPer ;		// save current value
        	GetDlgItemText(hDlg, IDC_E_NOPERIODSBELOW, szbelow, 30) ;
			LoPer = atof(szbelow) ;	// new value
			SetUDPos(U_PDB, (int)(100.0 * LoPer)) ;
			if (LoPer != oldLoPer) // if old and new differ
			{
				Refresh() ;
				SendMessage(hDlgSource, WM_COMMAND, TG_GET_ALIGNS, 0L) ;
			}
			if (PlotSynth || mPlotSynth) updisp() ;
			break ;

		case IDC_E_NOPERIODSABOVE:
			oldHiPer = HiPer ;
        	GetDlgItemText(hDlg, IDC_E_NOPERIODSABOVE, szabove, 30) ;
			HiPer = atof(szabove) ;
			SetUDPos(U_PDA, (int)(100.0 * HiPer)) ;
			if (HiPer != oldHiPer)
			{
				Refresh() ;
				SendMessage(hDlgSource, WM_COMMAND, TG_GET_ALIGNS, 0L) ;
			}
			if (PlotSynth || mPlotSynth) updisp() ;
			break ;

		case IDC_C_ALGRAPH:			// this is the cos^2 alignment graph
			PlotAlData = IsDlgButtonChecked(hDlg, IDC_C_ALGRAPH) ;
			 updisp() ;
			break ;

		case IDC_C_ALMODGRAPH:			// this is the modified cos^2 alignment graph
			PlotAlModData = IsDlgButtonChecked(hDlg, IDC_C_ALMODGRAPH) ;
			 updisp() ;
			break ;

		case IDC_C_RCMP:
			{
			PlotComp = IsDlgButtonChecked(hDlg, IDC_C_RCMP) ;
			if (PlotComp)
				EnableWindow(W1, TRUE) ;
			else
			{
					CheckDlgButton(hDlg, IDC_C_RSHF, 0) ;
					PlotShifts = 0 ;
					EnableWindow(W1, FALSE) ;
			}
			 updisp() ;
			}
			break ;

		case IDC_C_RSHF:
			PlotShifts = IsDlgButtonChecked(hDlg, IDC_C_RSHF) ;
			 updisp() ;
			break ;

		case IDC_C_RAGR:
			PlotAgraph = IsDlgButtonChecked(hDlg, IDC_C_RAGR) ;
			if (PlotAgraph)
			{
			  wantOneDay = 0 ;
			   wantBumps = 0 ;
			_is.rAgraphExists = 0 ;
             LPlotSynAgr = 0 ;
            mLPlotSynAgr = 0 ;
			SetAgrFlags2() ;
			}
			 updisp() ;
			break ;

		case IDC_C_RAGR_SYNTHETIC:

			LPlotSynAgr = IsDlgButtonChecked(hDlg, IDC_C_RAGR_SYNTHETIC) ;

				if (LPlotSynAgr)
				{
					SetAgrFlags2() ;
					wantBumps  = 0 ;
					wantOneDay = 1 ;
					_is.SynAgrExists = 0 ; // just force it every time - simplest!
				}

		    if (LPlotSynAgr && _is.DataExist)
			 {
			// Obtain the spectrum of the raw lambda data
			// a day at a time
			Spectrum(
				pSamp,
				samples,
				&(st.BOrdStep),
				st.BTopOrd,
				st.BBotOrd,
				RAW		 
				) ;

				   Synthesis(
			                 pSamp,
							 samples,
							 st.BBotOrd,
							 st.BTopOrd,
							 0.0,			// no resonant order	
							 0.0,			// no selectivity
							 0.0,			// no gain
							 0,				// not tuning
							 1,				// on the bud series
			                 RAW,			// using RAW lambda
							 0,				// not forcing
							 0,				// not alignments
							 0,				// not integrating
							 0				// not differentiating
						    ) ;
			 }
			 updisp() ;
			break ;

// Operations on Running Mean data

		case IDC_C_MDAT:
			mPlotData = IsDlgButtonChecked(hDlg, IDC_C_MDAT) ;
			updisp() ;
			break ;

		case IDC_C_MSYN:
			mPlotSynth = IsDlgButtonChecked(hDlg, IDC_C_MSYN) ;
			if (mPlotSynth)
			{
               if (!_is.mLamSpExists)
			   {
				   pSamp->mPeaks = 0 ;
				   SetWindowText(hWndFetch,"Mean Lam. Spectra") ;
				_is.mLamSpExists = GetLambdaSpectrum( MEAN ) ;
				   SetWindowText(hWndFetch,"") ;
			   }

			   if (!_is.mLamSnExists)
			   {
					wantBumps = 1 ; wantOneDay = 0 ;
				   SetWindowText(hWndFetch,"Mean Lambda Synth") ;
			    _is.mLamSnExists = GetLambdaSynthesis( MEAN, 0 ) ;
				   SetWindowText(hWndFetch,"") ;
			   }
			}
			updisp() ;
			break ;

		case IDC_C_MEANDIPS:

			PlotMeanDips = IsDlgButtonChecked(hDlg, IDC_C_MEANDIPS) ;
			 updisp() ;
			break ;

		case IDC_C_MEANTUNEDDIPS:

			PlotMeanTunedDips = IsDlgButtonChecked(hDlg, IDC_C_MEANTUNEDDIPS) ;
			 updisp() ;
			break ;

		case IDC_C_MEANPEAKS:

			PlotMeanPeaks = IsDlgButtonChecked(hDlg, IDC_C_MEANPEAKS) ;
			 updisp() ;
			break ;

		case IDC_C_MEANTUNEDPEAKS:

			PlotMeanTunedPeaks = IsDlgButtonChecked(hDlg, IDC_C_MEANTUNEDPEAKS) ;
			 updisp() ;
			break ;

		case IDC_C_MFSYNTH:	 // Forced synthesis of running mean lambdas

			// The amplitude of the components is forced to a
			// constant value. The synthesis reflects only the
			// phase distribution of the components.

			mPlotFSynth = IsDlgButtonChecked(hDlg, IDC_C_MFSYNTH) ;
			if (mPlotFSynth)
			{
               if (!_is.mLamSpExists)
			   {
				   pSamp->mPeaks = 0 ;
				   SetWindowText(hWndFetch,"Mean Lam. Spectra") ;
				_is.mLamSpExists = GetLambdaSpectrum( MEAN ) ;
				   SetWindowText(hWndFetch,"") ;
			   }
			   if (!_is.mLamFSnExists)
			   {
				   SetWindowText(hWndFetch,"Forced Synth") ;
				_is.mLamFSnExists = GetLambdaSynthesis( MEAN, 1 ) ;
				   SetWindowText(hWndFetch,"") ;
			   }
			}
			 updisp() ;
			break ;

		case IDC_C_MCMP:	// Mean Lambda fourier component at maxorder
			mPlotComp = IsDlgButtonChecked(hDlg, IDC_C_MCMP) ;
			if (mPlotComp && wantMovingMean)
				EnableWindow(W2, TRUE) ;
			else
			{
					CheckDlgButton(hDlg, IDC_C_MSHF, 0) ;
					mPlotShifts = 0 ;
					EnableWindow(W2, FALSE) ;
			}
            
			 updisp() ;
			break ;

		case IDC_C_MSHF:	// the above Component's time shift
							// relative to the _following_ alignment 
			mPlotShifts = IsDlgButtonChecked(hDlg, IDC_C_MSHF) ;
            
			 updisp() ;
			break ;

		case IDC_C_MAGR:
			mPlotAgraph = IsDlgButtonChecked(hDlg, IDC_C_MAGR) ;
			if (mPlotAgraph)
			{
			wantOneDay = 0 ;
			wantBumps = 0 ;
			 LPlotSynAgr = 0 ;
			mLPlotSynAgr = 0 ;
			_is.mAgraphExists = 0 ;
            SetAgrFlags2() ;
			}
			 updisp() ;
			break ;

		case IDC_C_MAGR_SYNTHETIC:
			mLPlotSynAgr = IsDlgButtonChecked(hDlg, IDC_C_MAGR_SYNTHETIC) ;
			if (mLPlotSynAgr)
			{
				SetAgrFlags2() ;
				wantBumps  = 0 ;
				wantOneDay = 1 ;
				_is.mSynAgrExists = 0 ; // just force it every time - simplest!
			}
			if (mLPlotSynAgr && _is.MeansExist)
			 {

			// Obtain the spectrum of the mean lambda data
			// a day at a time
			Spectrum(
				pFourier,
				bud,
				&(st.BOrdStep),
				st.BTopOrd,
				st.BBotOrd,
				MEAN		 
				) ;

				   Synthesis(
			                 pFourier,
							 bud,
							 st.BBotOrd,
							 st.BTopOrd,
							 0.0,			// no resonant order	
							 0.0,			// no selectivity
							 0.0,			// no gain
							 0,				// not tuning
							 1,				// on a bud series
			                 MEAN,			// using MEAN Lambda
							 0,				// not forcing
							 0,				// not alignments
							 0,				// not integrating
							 0				// not differentiating
						    ) ;
				 }
			 updisp() ;
			break ;

// Other operations

		case IDC_C_PHASES: // observed phase shift
			{
			PlotObsShift = IsDlgButtonChecked(hDlg, IDC_C_PHASES) ;
			 updisp() ;
			}
			break ;

		case IDC_C_PHASESHIFT:
			ShowShifts = IsDlgButtonChecked(hDlg, IDC_C_PHASESHIFT) ;
			updisp();
			break ;

		case IDC_C_TOLINK:
			toLink = IsDlgButtonChecked(hDlg, IDC_C_TOLINK) ;
			updisp();
			break ;

		case IDC_C_7DAYGRAT:
			Plot7daygrat = IsDlgButtonChecked(hDlg, IDC_C_7DAYGRAT) ;
			 updisp() ;
			break ;

		case IDC_C_AVEL: // angular "closure" rate

			PlotCRate = IsDlgButtonChecked(hDlg, IDC_C_AVEL) ;

			if (PlotCRate)  
			{
				    VelsOn() ;
					ep = align->epfirst ;
					update() ;
					if (!_is.AvelsExist)
					SendMessage(hDlgSource, WM_COMMAND, GET_ALIGN_DATA, 0L) ;
			}
       
			 updisp() ;

			break ;

		case IDC_C_CSQRATE:       // time rate of change of alignment
			
			PlotCsqRate = IsDlgButtonChecked(hDlg, IDC_C_CSQRATE) ;

			if (PlotCsqRate)  
			{
					VelsOn() ;
					ep = align->epfirst ;
					update() ;
					if (!_is.CsqRateExists || !_is.AvelsExist)
					SendMessage(hDlgSource, WM_COMMAND, GET_ALIGN_DATA, 0L) ;
			}
           
    		 updisp() ;

			break ;

		case IDC_C_MOD_ANOM:          // use modified Lunar anomaly
		wantModanom = IsDlgButtonChecked(hDlg, IDC_C_MOD_ANOM) ;

		if (wantModanom)
		{
                   modPlotAligns = 1 ; // toggle the modified Alignment arrows on
				   EnableWindow(GetDlgItem(hDlg, IDC_C_LINK_MOD_ALS),  TRUE) ; // allow links
				   EnableWindow(GetDlgItem(hDlg, IDC_C_PRED_PHASES),   TRUE) ; // turn on predictions button
				   EnableWindow(GetDlgItem(hDlg, IDC_C_ALMODGRAPH),    TRUE) ;
				    updisp() ;
		}
		else
		{
					modPlotAligns = 0 ;
					EnableWindow(GetDlgItem(hDlg, IDC_C_LINK_MOD_ALS),  FALSE) ; // disallow links
					EnableWindow(GetDlgItem(hDlg, IDC_C_PRED_PHASES),   FALSE) ;
					EnableWindow(GetDlgItem(hDlg, IDC_C_ALMODGRAPH),    FALSE) ;
					updisp() ;
		}
			break ;

		case IDC_C_ALIG:          // show/hide alignment arrows

			if( IsDlgButtonChecked(hDlg, IDC_C_ALIG) )
		{
aligs:		if (_is.AlignsExist)	  // if alignments there
			{
				if ( st.TimeSeries )
				{
				   PlotAligns = 1 ; // toggle the Alignment arrows on
				   EnableWindow(GetDlgItem(hDlg, IDC_C_LINK_ALS),  TRUE) ;
				   if (_is.modAlignsExist)	// turn on predictions button if modified aligns exist
				   EnableWindow(GetDlgItem(hDlg, IDC_C_PRED_PHASES),  TRUE) ;
                    updisp() ;
				}
			}
			else // Alignments not there, go get them.
			{
				SendMessage(hDlgSource, WM_COMMAND, TG_GET_ALIGNS, 0L) ;
				// it that works, try again
			    if (_is.AlignsExist)
				{
					// this is a new set of Alignments,
					// so existing Agraph(s) rendered invalid. 
					_is.mAgraphExists = _is.rAgraphExists = 0 ;
					goto aligs ;
				}
				// else report and forget.
				msgbox = 1 ;
				MessageBox(NULL,"The Alignments were Not Found",
					            "Problem: Alignments ",
						         MB_ICONEXCLAMATION|MB_OK) ;
				msgbox = 0 ;
			}
		}
			else
			{
				PlotAligns = 0 ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_LINK_ALS),  FALSE) ;
			     updisp() ;
			}

			break ;

		case IDC_C_LINK_ALS:
			wantAlIconLinks = IsDlgButtonChecked(hDlg, IDC_C_LINK_ALS) ;
			 updisp() ;
			break ;

		case IDC_C_LINK_MOD_ALS:
			wantModAlIconLinks = IsDlgButtonChecked(hDlg, IDC_C_LINK_MOD_ALS) ;
			 updisp() ;
			break ;

		case IDC_C_PRED_PHASES:
			wantPredSh = IsDlgButtonChecked(hDlg, IDC_C_PRED_PHASES) ;
			 updisp() ;
			break ;

		case IDC_E_MSPAN:  // span value has changed in edit box
		  tSpan = SetTimer(hDlg, IDT_MSPAN, hold, NULL) ;
	    TempVal = GetDlgItemInt(hDlg,IDC_E_MSPAN,&snafu,FALSE) ;
		break;

        case TG_MSPAN:
		if (TempVal != MeanSpan)
		{
		// Force a re-evaluation of the means
		// Make sure MeanSpan is odd.

			if (!(TempVal % 2)) // if TempVal is even
			{
			if (TempVal > MeanSpan)      // going up.
			  {
				MeanSpan = TempVal + 1 ; // so one more.
			  }
			else
			if (TempVal < MeanSpan)      // going down.
			  {
				MeanSpan = TempVal - 1 ; // so one fewer
			  }
			}
			else // TempVal is odd. It's OK.
		  MeanSpan = TempVal ;

		SetDlgItemInt(hDlg, IDC_E_MSPAN, MeanSpan, FALSE) ;

		  _is.MeansExist = 0 ;

		  if (_is.DataExist)
		  SendMessage(hDlg, WM_COMMAND, TG_MOVMEAN, 0L) ;

		  // Spectrum, Synthesis, Lambda-Dips and Peaks all
		  // invalidated, update on next requests for them
		  _is.mLamSpExists = _is.mLamSnExists = 0 ;
		  _is.MeanDipsExist = _is.MeanTunedDipsExist = 0 ;
		}
			break ;

		default:
			break ;
		} // switch(LOWORD(wParam))
		break ; // WM_COMMAND

	default:
		break ;
	} // switch (msg)

  return FALSE ;
} // TabDisplay

void IsRast( void )
{
	RECT r ;
	BOOL B ;
	 int p ;
	if (PlotRaster)
	{
		// 
		for (p = MER, B = FALSE ; p <= SUN ; p++)
		{
			if (p == PLU) continue ;
			if (RastBodyList[p]) B = TRUE ;
			break ;
		}
		EnableWindow(GetDlgItem(hRastDlg, IDC_C_ALL_ALS), B) ;
		GetClientRect(hWndRast, &r) ;
		ivrc(hWndRast, &r, TRUE) ;
	}
}

void ClearBodyIncList( HWND hDlg )
{
	int i ;
	 for (i  = EAR ;
	      i <= SUN ;
		  BodyList[i++] = 0) ;

	CheckDlgButton(hDlg, IDC_C_SUN,    0) ;
    CheckDlgButton(hDlg, IDC_C_EAR,    0) ;
    CheckDlgButton(hDlg, IDC_C_MOO,    0) ;
    CheckDlgButton(hDlg, IDC_C_MER,    0) ;
    CheckDlgButton(hDlg, IDC_C_VEN,    0) ;
    CheckDlgButton(hDlg, IDC_C_MAR,    0) ;
    CheckDlgButton(hDlg, IDC_C_JUP,    0) ;
    CheckDlgButton(hDlg, IDC_C_SAT,    0) ;
    CheckDlgButton(hDlg, IDC_C_URA,    0) ;
    CheckDlgButton(hDlg, IDC_C_NEP,    0) ;
}

void SetBodyIncList( HWND hDlg )
{
	int i ;
	 for (i  = EAR ;
	      i <= SUN ;
		  BodyList[i++] = 1) ;

	CheckDlgButton(hDlg, IDC_C_SUN,    1) ;
    CheckDlgButton(hDlg, IDC_C_EAR,    1) ;
    CheckDlgButton(hDlg, IDC_C_MOO,    1) ;
    CheckDlgButton(hDlg, IDC_C_MER,    1) ;
    CheckDlgButton(hDlg, IDC_C_VEN,    1) ;
    CheckDlgButton(hDlg, IDC_C_MAR,    1) ;
    CheckDlgButton(hDlg, IDC_C_JUP,    1) ;
    CheckDlgButton(hDlg, IDC_C_SAT,    1) ;
    CheckDlgButton(hDlg, IDC_C_URA,    1) ;
    CheckDlgButton(hDlg, IDC_C_NEP,    1) ;
}

void ClearNonBodyIncList ( HWND hDlg )
{
    CheckDlgButton(hDlg, IDC_C_EQN,    0) ;	 // non bodies
    CheckDlgButton(hDlg, IDC_C_LEQ,    0) ;
    CheckDlgButton(hDlg, IDC_C_INODAL, 0) ;
    CheckDlgButton(hDlg, IDC_C_PERI,   0) ;
    CheckDlgButton(hDlg, IDC_C_MOT,    0) ;
    //CheckDlgButton(hDlg, IDC_C_PGEE,   0) ;

		      BodyList[NOD] =
			   BodyList[EQN] =
			    BodyList[LEQ] =
			     BodyList[PER] =
			      BodyList[MOT] = 
				   BodyList[PRG] = 0 ;

}

void SetNonBodyIncList ( HWND hDlg )
{
    CheckDlgButton(hDlg, IDC_C_EQN,    1) ;	 // non bodies
    CheckDlgButton(hDlg, IDC_C_LEQ,    1) ;
    CheckDlgButton(hDlg, IDC_C_INODAL, 1) ;
    CheckDlgButton(hDlg, IDC_C_PERI,   1) ;
    CheckDlgButton(hDlg, IDC_C_MOT,    1) ;
    //CheckDlgButton(hDlg, IDC_C_PGEE,   0) ;

		      BodyList[NOD] =
			   BodyList[EQN] =
			    BodyList[LEQ] =
			     BodyList[PER] =
			      BodyList[MOT] = 
				   BodyList[PRG] = 1 ;

}

void ClearBodyDirList( HWND hDlg )
{
	int i ;

	for ( i  = EAR ;
	      i <= SUN ;
		  DirBody[i++] = 0) ;

	CheckDlgButton(hDlg, IDC_C_DIR_EAR,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_MOO,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_MER,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_VEN,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_MAR,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_JUP,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_SAT,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_URA,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_NEP,    0) ;
    CheckDlgButton(hDlg, IDC_C_DIR_SUN,    0) ;
}

void SetBodyDirList( HWND hDlg )
{
	int i ;

	for ( i  = EAR ;
	      i <= SUN ;
		  DirBody[i++] = 1) ;

	CheckDlgButton(hDlg, IDC_C_DIR_EAR,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_MOO,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_MER,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_VEN,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_MAR,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_JUP,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_SAT,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_URA,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_NEP,    1) ;
    CheckDlgButton(hDlg, IDC_C_DIR_SUN,    1) ;
}

void ClearBodyAccList( HWND hDlg )
{
	int i ;

	for ( i  = EAR ;
	      i <= SUN ;
		  AccBody[i++] = 0) ;

	CheckDlgButton(hDlg, IDC_C_ACC_EAR,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_MOO,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_MER,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_VEN,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_MAR,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_JUP,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_SAT,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_URA,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_NEP,    0) ;
    CheckDlgButton(hDlg, IDC_C_ACC_SUN,    0) ;
}

void SetBodyAccList( HWND hDlg )
{
	int i ;

	for ( i  = EAR ;
	      i <= SUN ;
		  AccBody[i++] = 1) ;

	CheckDlgButton(hDlg, IDC_C_ACC_EAR,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_MOO,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_MER,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_VEN,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_MAR,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_JUP,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_SAT,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_URA,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_NEP,    1) ;
    CheckDlgButton(hDlg, IDC_C_ACC_SUN,    1) ;
}


BOOL CALLBACK TabSystemicDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static BOOL BO ;
	static i ;

	switch (msg)
	{

	case WM_INITDIALOG:

			 CheckRadioButton(hDlg,
				 IDC_R_SHOW_SHIFT,
				 IDC_R_SHOW_SHIFTED,
				 IDC_R_SHOW_SHIFT) ;

			 CheckRadioButton(hDlg,
				 IDC_R_GEOC_DIRS,
				 IDC_R_MB_DIRS,
				 IDC_R_GEOC_DIRS) ;

			 CheckRadioButton(hDlg,
				 IDC_R_HELIOC_MOTS,
				 IDC_R_GEOC_MOTS,
				 IDC_R_GEOC_MOTS) ;


// Nothing in Body Lists

				   ClearBodyIncList( hDlgSelectBody ) ;
				ClearNonBodyIncList( hDlg ) ;
				   ClearBodyDirList( hDlg ) ;

	OnChildDialogInit(hDlg) ;
		return TRUE ;

	case WM_COMMAND:

		switch (LOWORD(wParam))
		{

		case IDC_C_SEL_LONG: // Chart the selected body-direction(s)
			{
				BOOL B ;
			PlotSelLong = IsDlgButtonChecked(hDlg, IDC_C_SEL_LONG) ;
					  B = (PlotSelLong || PlotMBDirreSun) ? TRUE : FALSE ;
				EnableWindow(GetDlgItem(hDlg, IDC_R_GEOC_DIRS),   B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_R_HELIOC_DIRS), B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_R_MB_DIRS),     B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_SUN),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_EAR),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_MER),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_VEN),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_MAR),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_JUP),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_SAT),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_NEP),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_URA),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DIR_MOO),    B) ;
            
			 updisp() ;
			}
			break ;

		case IDC_C_ACC_BODIES: // Chart the selected body-acceleration(s)
			{
				BOOL B ;
			PlotAccBodies = IsDlgButtonChecked(hDlg, IDC_C_ACC_BODIES) ;
					  B = (PlotAccBodies) ? TRUE : FALSE ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_SUN),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_EAR),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_MER),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_VEN),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_MAR),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_JUP),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_SAT),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_NEP),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_URA),    B) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ACC_MOO),    B) ;
            
			 updisp() ;
			}
			break ;

		case IDC_R_GEOC_DIRS:
			do_geoc_dirs = IsDlgButtonChecked(hDlg, IDC_R_GEOC_DIRS) ;
			if (do_geoc_dirs) do_meanbody_dirs = do_helioc_dirs = 0 ;
            
			 updisp() ;
			break ;


		case IDC_R_HELIOC_DIRS:
			do_helioc_dirs = IsDlgButtonChecked(hDlg, IDC_R_HELIOC_DIRS) ;
			if (do_helioc_dirs)	do_meanbody_dirs = do_geoc_dirs = 0 ;
            
			 updisp() ;
			break ;

		case IDC_R_MB_DIRS:
			do_meanbody_dirs = IsDlgButtonChecked(hDlg, IDC_R_MB_DIRS) ;
			if (do_meanbody_dirs) do_helioc_dirs = do_geoc_dirs = 0 ;
 			 updisp() ;
			break ;


// Geocentric, Heliocentric or On-Mean-Body Directions per body

		case IDC_B_DIR_ALL:
			SetBodyDirList( hDlg ) ;
			 updisp() ;
				break ;

		case IDC_B_DIR_NONE:
			ClearBodyDirList( hDlg ) ;
			 updisp() ;
				break ;

		case IDC_C_DIR_SUN:
			DirBody[SUN] = IsDlgButtonChecked(hDlg, IDC_C_DIR_SUN) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_EAR:
			DirBody[EAR] = IsDlgButtonChecked(hDlg, IDC_C_DIR_EAR) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_MER:
			DirBody[MER] = IsDlgButtonChecked(hDlg, IDC_C_DIR_MER) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_VEN:
			DirBody[VEN] = IsDlgButtonChecked(hDlg, IDC_C_DIR_VEN) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_MAR:
			DirBody[MAR] = IsDlgButtonChecked(hDlg, IDC_C_DIR_MAR) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_JUP:
			DirBody[JUP] = IsDlgButtonChecked(hDlg, IDC_C_DIR_JUP) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_SAT:
			DirBody[SAT] = IsDlgButtonChecked(hDlg, IDC_C_DIR_SAT) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_URA:
			DirBody[URA] = IsDlgButtonChecked(hDlg, IDC_C_DIR_URA) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_NEP:
			DirBody[NEP] = IsDlgButtonChecked(hDlg, IDC_C_DIR_NEP) ;
			 updisp() ;
			break ;

		case IDC_C_DIR_MOO:
			DirBody[MOO] = IsDlgButtonChecked(hDlg, IDC_C_DIR_MOO) ;
			 updisp() ;
			break ;

//  Accelerations per body

		case IDC_B_ACC_ALL:
			SetBodyAccList( hDlg ) ;
			 updisp() ;
				break ;

		case IDC_B_ACC_NONE:
			ClearBodyAccList( hDlg ) ;
			 updisp() ;
				break ;

		case IDC_C_ACC_SUN:
			AccBody[SUN] = IsDlgButtonChecked(hDlg, IDC_C_ACC_SUN) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_EAR:
			AccBody[EAR] = IsDlgButtonChecked(hDlg, IDC_C_ACC_EAR) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_MER:
			AccBody[MER] = IsDlgButtonChecked(hDlg, IDC_C_ACC_MER) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_VEN:
			AccBody[VEN] = IsDlgButtonChecked(hDlg, IDC_C_ACC_VEN) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_MAR:
			AccBody[MAR] = IsDlgButtonChecked(hDlg, IDC_C_ACC_MAR) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_JUP:
			AccBody[JUP] = IsDlgButtonChecked(hDlg, IDC_C_ACC_JUP) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_SAT:
			AccBody[SAT] = IsDlgButtonChecked(hDlg, IDC_C_ACC_SAT) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_URA:
			AccBody[URA] = IsDlgButtonChecked(hDlg, IDC_C_ACC_URA) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_NEP:
			AccBody[NEP] = IsDlgButtonChecked(hDlg, IDC_C_ACC_NEP) ;
			 updisp() ;
			break ;

		case IDC_C_ACC_MOO:
			AccBody[MOO] = IsDlgButtonChecked(hDlg, IDC_C_ACC_MOO) ;
			 updisp() ;
			break ;

// Systemic Angular Shift per body
//(being the shift brought about by the inclusion of the body)


// Systemic Direction per body


// Systemic Alignments per body


// Systemic Dispersion per body

		default:
			break ;

		}// switch (LOWORD(wParam))

		break ; // WM_COMMAND

	default:
		break ;
	} // switch( msg )

  return FALSE ;
} // TabSystemic

BOOL CALLBACK TabFourierDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
static HWND hW, hOK ;
static HWND hASTOK ;

static HWND U_LU, U_HU, U_SO ;
static HWND U_ASTLU, U_ASTHU ;
double oldord, oldastord ;
  char buff[255] ;

	switch (msg)
	{
	case WM_INITDIALOG:

		U_HU = GetDlgItem(hDlg, IDC_U_HORD) ;
		U_LU = GetDlgItem(hDlg, IDC_U_LORD) ;

		 hOK = GetDlgItem(hDlg, IDOK) ;

	    SetUDRng(U_HU, 1000, 0) ;
	    SetUDRng(U_LU, 1000, 0) ;
	    SetUDRng(U_SO, 1000, 0) ;

        st.BTopOrd   = 30.0 ;              // default Fourier Top Order for bud series
		st.BBotOrd   =  0.0 ;			  // default Fourier Low Order for bud series
		st.BOrdStep = (st.BTopOrd - st.BBotOrd) / 500.0 ;

		sprintf(buff, "%7.6f", st.BTopOrd) ;
		SetDlgItemText(hDlg, IDC_E_HORD, buff) ;
		sprintf(buff, "%7.6f", st.BBotOrd) ;
		SetDlgItemText(hDlg, IDC_E_LORD, buff) ;

		U_ASTHU = GetDlgItem(hDlg, IDC_U_ASTHORD) ;
		U_ASTLU = GetDlgItem(hDlg, IDC_U_ASTLORD) ;

		 hASTOK = GetDlgItem(hDlg, IDASTOK) ;

	    SetUDRng(U_ASTHU, 1000, 0) ;
	    SetUDRng(U_ASTLU, 1000, 0) ;

        st.ATopOrd   = 30.0 ;           // default Fourier Top Order for astron series
		st.ABotOrd   =  0.0 ;			// default Fourier Low Order for astron series
		st.AOrdStep  = (st.ATopOrd - st.ABotOrd) / 500.0 ; // default order step

		sprintf(buff, "%7.6f", st.ATopOrd) ;
		SetDlgItemText(hDlg, IDC_E_ASTHORD, buff) ;
		sprintf(buff, "%7.6f", st.ABotOrd) ;
		SetDlgItemText(hDlg, IDC_E_ASTLORD, buff) ;

	OnChildDialogInit(hDlg) ;
		return TRUE ;

	case WM_VSCROLL:

		   hW = (HWND)lParam ;

		   if (hW == U_LU)  // lo-order u/d changed
		   {
				// NOT a set buddy integer u/d ctl.
				// so get the changed position, multiply by factor,
				// and write to edit box.
		      oldord = st.BBotOrd ;

	        st.BBotOrd = 0.1 * (double)GetUDPos(U_LU) ;
			   
	              sprintf(buff,"%7.5f",st.BBotOrd) ;
				  SetDlgItemText(hDlg,IDC_E_LORD,buff) ;
				  st.BOrdStep = (st.BTopOrd - st.BBotOrd) / 500.0 ;
			if (oldord != st.BBotOrd) EnableWindow(hOK, TRUE) ;
		   }

		   if (hW == U_HU)	 // hi-order u/d changed
		   {
				// NOT a set buddy integer u/d ctl.
				// so get the changed position, multiply by factor,
				// and write to edit box.
			oldord = st.BTopOrd ;

	        st.BTopOrd = 0.1 * (double)GetUDPos(U_HU) ;
			   
	              sprintf(buff,"%7.5f",st.BTopOrd) ;
				  SetDlgItemText(hDlg,IDC_E_HORD,buff) ;
				  st.BOrdStep = (st.BTopOrd - st.BBotOrd) / 500.0 ;
			if (oldord != st.BTopOrd) EnableWindow(hOK, TRUE) ;
		   }

		   if (hW == U_ASTLU)  // lo-order u/d changed
		   {
				// NOT a set buddy integer u/d ctl.
				// so get the changed position, multiply by factor,
				// and write to edit box.
		      oldastord = st.ABotOrd ;

	        st.ABotOrd = 0.1 * (double)GetUDPos(U_ASTLU) ;
			   
	              sprintf(buff,"%7.5f",st.ABotOrd) ;
				  SetDlgItemText(hDlg,IDC_E_ASTLORD,buff) ;
				  st.AOrdStep = (st.ATopOrd - st.ABotOrd) / 500.0 ;
			if (oldastord != st.ABotOrd) EnableWindow(hASTOK, TRUE) ;
		   }

		   if (hW == U_ASTHU)	 // hi-order u/d changed
		   {
				// NOT a set buddy integer u/d ctl.
				// so get the changed position, multiply by factor,
				// and write to edit box.
			oldastord = st.ATopOrd ;

	        st.ATopOrd = 0.1 * (double)GetUDPos(U_ASTHU) ;
			   
	              sprintf(buff,"%7.5f",st.ATopOrd) ;
				  SetDlgItemText(hDlg,IDC_E_ASTHORD,buff) ;
				  st.AOrdStep = (st.ATopOrd - st.ABotOrd) / 500.0 ;
			if (oldastord != st.ATopOrd) EnableWindow(hASTOK, TRUE) ;
		   }

		break ;

	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
			// Applies to a bud series:
			// cancels all spectra, synthesese
			// and tuned synthesese pertaining
			// to the current series, and all
			// dips and peaks found on them.
			// They will be regenerated on
			// existing or new requests for them.

			case IDOK:

		_is.LamSpExists =
		 _is.mLamSpExists = 
		  _is.LamSnExists =
		   _is.mLamSnExists =
		    _is.LamFSnExists =
			 _is.mLamFSnExists =
			    pSamp->Peaks =
			     pSamp->mPeaks = 0 ;

		         _is.RawDipsExist =
		          _is.MeanDipsExist =
		           _is.RawPeaksExist =
		            _is.MeanPeaksExist = 0 ;
 
		      _is.RawTunedDipsExist =
		       _is.MeanTunedDipsExist = 
		        _is.RawTunedPeaksExist =
		         _is.MeanTunedPeaksExist = 0 ;

				 updisp() ;

				EnableWindow(hASTOK, FALSE) ;

			break ;

		    case IDASTOK:

				ep = align->epfirst ;
				update() ;

		// zero the progress bar
        if (hWndPB1 != NULL)
        SendMessage(hWndPB1, PBM_SETPOS, (WPARAM)0, 0) ;
		SetWindowText(hWndFetch,"Alignment Data") ;

		SendMessage(hDlgSource, WM_COMMAND, GET_ALIGN_DATA, 0L) ;

		// This invalidates Astronomic spectra, spectral peaks
		// and synthesese. They will be rebuilt on existing
		// or new requests for them.

			   pFourier->Peaks =
			   pFourier->mPeaks = 0 ;

		       if (pAlFou != NULL)
			   {
			        pAlFou->Peaks =
			         pAlFou->mPeaks =
					  _is.ALNSpExists = 0 ;
			   }
				  updisp() ;
			     EnableWindow(hOK, FALSE) ;

			break ;

		    case IDC_E_HORD:            // top order changed in edit box
			oldord = st.BTopOrd ;
			// (Re)build not needed
        	GetDlgItemText(hDlg,IDC_E_HORD,buff,20) ;
			st.BTopOrd  = atof(buff) ;      // get it and calc. order step
			st.BOrdStep = (st.BTopOrd - st.BBotOrd) / 500.0 ;
			SetUDPos(U_HU, (int)(10.0 * st.BTopOrd)) ;
			if (oldord != st.BTopOrd) EnableWindow(hOK, TRUE) ;
				break ;

		    case IDC_E_LORD:            // bottom order changed in edit box
			oldord = st.BBotOrd ;
			// (Re)build not needed
        	GetDlgItemText(hDlg,IDC_E_LORD,buff,20) ;
			st.BBotOrd  = atof(buff) ;      // get it and calc. order step
			st.BOrdStep = (st.BTopOrd - st.BBotOrd) / 500.0 ;
			SetUDPos(U_LU, (int)(10.0 * st.BBotOrd)) ;
			if (oldord != st.BBotOrd) EnableWindow(hOK, TRUE) ;
				break ;

		    case IDC_E_ASTHORD:            // top order changed in edit box
			oldastord = st.ATopOrd ;
			// (Re)build not needed
        	GetDlgItemText(hDlg,IDC_E_ASTHORD,buff,20) ;
			st.ATopOrd  = atof(buff) ;      // get it and calc. order step
			st.AOrdStep = (st.ATopOrd - st.ABotOrd) / 500.0 ;
			SetUDPos(U_ASTHU, (int)(10.0 * st.ATopOrd)) ;
			if (oldastord != st.ATopOrd) EnableWindow(hASTOK, TRUE) ;
				break ;

		    case IDC_E_ASTLORD:            // bottom order changed in edit box
			oldastord = st.ABotOrd ;
			// (Re)build not needed
        	GetDlgItemText(hDlg,IDC_E_ASTLORD,buff,20) ;
			st.ABotOrd  = atof(buff) ;      // get it and calc. order step
			st.AOrdStep = (st.ATopOrd - st.ABotOrd) / 500.0 ;
			SetUDPos(U_LU, (int)(10.0 * st.ABotOrd)) ;
			if (oldastord != st.ABotOrd) EnableWindow(hASTOK, TRUE) ;
				break ;

		default:
			break ;
		} // switch(LOWORD(wParam))
		break ; // WM_COMMAND

	default:
		break ;
	} // switch(msg)

  return FALSE ;
} // TabFourier

BOOL CALLBACK TabTunedDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static HWND hW ;
	static HWND U_RO, U_ROB, E_RO, E_ROB, U_SL, E_SL, U_GN, E_GN ;
	static HICON hicopass, hiconotch ;
		   char buff[50] ;

	switch (msg)
	{
	case WM_INITDIALOG:
		U_RO = GetDlgItem(hDlg, IDC_U_RESORDER) ;
		E_RO = GetDlgItem(hDlg, IDC_E_RESORDER) ;
				SetUDRng(U_RO,  10000, 0) ;
                sprintf(buff,"%4.3f", resorder) ;
				SetDlgItemText(hDlg,IDC_E_RESORDER,buff) ;
				SetUDPos(U_RO,  (int)(10.0 * resorder)) ;

	   U_ROB = GetDlgItem(hDlg, IDC_U_RESORDERBUD) ;
	   E_ROB = GetDlgItem(hDlg, IDC_E_RESORDERBUD) ;
				SetUDRng(U_ROB, 10000, 0) ;
                sprintf(buff,"%4.3f", resorderbud) ;
				SetDlgItemText(hDlg,IDC_E_RESORDERBUD,buff) ;
				SetUDPos(U_ROB, (int)(10.0 * resorderbud)) ;

		U_SL = GetDlgItem(hDlg, IDC_U_SELECTIVITY) ;
		E_SL = GetDlgItem(hDlg, IDC_E_SELECTIVITY) ;
				SetUDRng(U_SL, 10000, 0) ;
                sprintf(buff,"%4.3f", selectivity) ;
				SetDlgItemText(hDlg,IDC_E_SELECTIVITY,buff) ;
				SetUDPos(U_SL, (int)(10.0 * selectivity)) ;

		U_GN = GetDlgItem(hDlg, IDC_U_SEL_GAIN) ;
		E_GN = GetDlgItem(hDlg, IDC_E_SEL_GAIN) ;
				SetUDRng(U_GN, 10000, 0) ;
                sprintf(buff,"%4.3f", gain) ;
				SetDlgItemText(hDlg,IDC_E_SEL_GAIN,buff) ;
				SetUDPos(U_GN, (int)(10.0 * gain)) ;

		hicopass  = LoadIcon(hInst, MAKEINTRESOURCE(IDI_IC_BPASS) ) ;
		SendDlgItemMessage(hDlg, IDC_R_BPASS, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hicopass ) ;

		hiconotch = LoadIcon(hInst, MAKEINTRESOURCE(IDI_IC_NOTCH)) ;
		SendDlgItemMessage(hDlg, IDC_R_NOTCH, BM_SETIMAGE, (WPARAM)IMAGE_ICON, (LPARAM)hiconotch) ;

		CheckRadioButton(hDlg,			// start with default resonance order
			             IDC_R_MIAPORD,
			             IDC_R_DFLTORD,
						 IDC_R_MIAPORD
						) ;

		CheckRadioButton(hDlg,			// Mars as default
			             IDC_R_TSUN,
			             IDC_R_TNEP,
						 IDC_R_TMAR
						) ;

		CheckRadioButton(hDlg,			// 'Pass' as default
			             IDC_R_BPASS,
			             IDC_R_NOTCH,
						 IDC_R_BPASS
						) ;

	OnChildDialogInit(hDlg) ;
		return TRUE ;

	case CLOSEALL: // is expandable

		if (IsDlgButtonChecked(hDlg, IDC_C_SHOW_CURVE))
		{
			CheckDlgButton(hDlg, IDC_C_SHOW_CURVE, 0) ;
			ShowWindow(hWndTune, SW_HIDE) ;
		}
		break ;

	case WM_VSCROLL:

		hW = (HWND)lParam ;
		
		if (hW == U_RO)
		{
			// NOT a buddy integer u/d ctl, so go get the position
		    // and multiply it by the factor
                 resorder = 0.1 * (double)GetUDPos(U_RO) ;
					
			// write the value to the edit ctl
                sprintf(buff,"%4.3f", resorder) ;
				SetDlgItemText(hDlg,IDC_E_RESORDER,buff) ;
		}

		if (hW == U_ROB)
		{
			// NOT a buddy integer u/d ctl, so go get the position
		    // and multiply it by the factor
                 resorderbud = 0.1 * (double)GetUDPos(U_ROB) ;
					
			// write the value to the edit ctl
                sprintf(buff,"%4.3f", resorderbud) ;
				SetDlgItemText(hDlg,IDC_E_RESORDERBUD,buff) ;
		}

		if (hW == U_SL)
		{
			// NOT a buddy integer u/d ctl
                 selectivity = 0.1 * (double)GetUDPos(U_SL) ;
					
			// write the value to the edit ctl
                sprintf(buff,"%4.3f", selectivity) ;
				SetDlgItemText(hDlg,IDC_E_SELECTIVITY,buff) ;
		}

		if (hW == U_GN)
		{
			// NOT a buddy integer u/d ctl
                gain = (double)GetUDPos(U_GN) ;
					
			// write the value to the edit ctl
                sprintf(buff,"%4.3f", 0.1 * gain) ;
				SetDlgItemText(hDlg,IDC_E_SEL_GAIN,buff) ;
		}

		return 0L ;
		break ;

	case WM_COMMAND:

		switch (HIWORD(wParam))
	  {
		case EN_CHANGE:

			switch(LOWORD(wParam))
			{
		case IDC_E_RESORDER:    // Resonant Order edit box changed
			GetDlgItemText(hDlg, IDC_E_RESORDER,   buff, 50) ;
			   resorder = atof(buff) ;
			resorderbud = BudGP * resorder / AstGP ; // match the bud resonant order to it
			SetUDPos(U_RO,  (int)(10.0 * resorder)) ;
			SetUDPos(U_ROB, (int)(10.0 * resorderbud)) ;
			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ;
			break ;

		case IDC_E_RESORDERBUD:    // Resonant Order for Bud Series edit box changed
			GetDlgItemText(hDlg, IDC_E_RESORDERBUD,   buff, 50) ;
			resorderbud = atof(buff) ;
			resorder = AstGP * resorderbud / BudGP ;
			SetUDPos(U_ROB, (int)(10.0 * resorderbud)) ;
			SetUDPos(U_RO,  (int)(10.0 * resorder)) ;

		// the current peaks and dips are now invalid

	 _is.RawTunedDipsExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_RAWTUNEDDIPS,   0) ;
	_is.RawTunedPeaksExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_RAWTUNEDPEAKS,  0) ;
	_is.MeanTunedDipsExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_MEANTUNEDDIPS,  0) ;
   _is.MeanTunedPeaksExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_MEANTUNEDPEAKS, 0) ;

			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ;
			break ;

		case IDC_E_SELECTIVITY:	// Selectivity edit box changed
			GetDlgItemText(hDlg, IDC_E_SELECTIVITY,buff, 50) ;
			selectivity = atof(buff) ;
			SetUDPos(U_SL, (int)(10.0 * selectivity)) ;

		// the current peaks and dips are now invalid
	 _is.RawTunedDipsExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_RAWTUNEDDIPS,   0) ;
	_is.MeanTunedDipsExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_RAWTUNEDPEAKS,  0) ;
	_is.RawTunedPeaksExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_MEANTUNEDDIPS,  0) ;
   _is.MeanTunedPeaksExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_MEANTUNEDPEAKS, 0) ;

			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ;
			break ;

		case IDC_E_SEL_GAIN:	// Transfer Gain edit box changed
			GetDlgItemText(hDlg, IDC_E_SEL_GAIN,   buff, 50) ;
			gain = atof(buff) ;
			SetUDPos(U_GN, (int)(10.0 * gain)) ;

		// the current peaks and dips are now invalid
	 _is.RawTunedDipsExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_RAWTUNEDDIPS,   0) ;
	_is.MeanTunedDipsExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_RAWTUNEDPEAKS,  0) ;
	_is.RawTunedPeaksExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_MEANTUNEDDIPS,  0) ;
   _is.MeanTunedPeaksExist = 0 ; CheckDlgButton(hDlgDisplay, IDC_C_MEANTUNEDPEAKS, 0) ;

			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ;
			break ;

		default:
			break ;
			} // switch (LOWORD(wParam))

			break ; // EN_UPDATE

			default:
				break ;
		} // switch(HIWORD(wParam))

		switch(LOWORD(wParam)) // Deal with buttons now
		{
		case IDOK:
		    if (LPlotSynTune && _is.DataExist)
			 {
				 wantBumps = 1 ;
				wantOneDay = 0 ;
				DoTunedSynth(
			                 pSamp,
							 samples,
							 4,
							 st.BBotOrd,
							 st.BTopOrd,
							 &(st.BOrdStep),
							 1,
			                 RAW
						    ) ;
			     updisp() ;
			 }

			if (mLPlotSynTune && _is.MeansExist)
			 {
				 wantBumps = 1 ;
				wantOneDay = 0 ;
				DoTunedSynth(
					         pSamp,
							 samples,
							 4,
							 st.BBotOrd,
							 st.BTopOrd,
							 &(st.BOrdStep),
							 1,
							 MEAN
							) ;
				 updisp() ;
			 }
		     EnableWindow(GetDlgItem(hDlg,IDOK), FALSE) ;
			break ;

		case IDC_C_SHOW_CURVE:
			ShowSelCrv = IsDlgButtonChecked(hDlg, IDC_C_SHOW_CURVE) ;
			if (ShowSelCrv)
			{
				ShowWindow(hWndTune, SW_SHOW) ;
				UpdateWindow(hWndTune) ;
			}
			else
				ShowWindow(hWndTune, SW_HIDE) ;
			break ;

		case IDC_C_TUNE_RAW_LAMBDA:
			LPlotSynTune = IsDlgButtonChecked(hDlg,IDC_C_TUNE_RAW_LAMBDA) ;
			if (LPlotSynTune)							// if to do
			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ; // turn on OK button
			updisp() ;									// wipe existing

			break ;

		case IDC_C_TUNE_MEAN_LAMBDA:
		   mLPlotSynTune= IsDlgButtonChecked(hDlg,IDC_C_TUNE_MEAN_LAMBDA) ;
			if (mLPlotSynTune)							// if to do
			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ; // turn on OK button
			else										// else

			PlotTunedSynthMeanLambdaSeries() ;	

			 //updisp() ;									// wipe existing


			break ;

		case IDC_R_MIAPORD : // select order of the mIAP 
			if (IsDlgButtonChecked(hDlg,IDC_R_MIAPORD) && _is.AlignsExist)
			{
			    //VelsOff() ;
			   resorder = st.pord ;						// derived from the mean IAP over the AstGP
			resorderbud = BudGP * resorder / AstGP ;	// this is the component's order wrt the BudGP
                sprintf(buff,"%4.3f", resorder) ;
				SetDlgItemText(hDlg,IDC_E_RESORDER, buff) ;
                sprintf(buff,"%4.3f", resorderbud) ;
				SetDlgItemText(hDlg,IDC_E_RESORDERBUD, buff) ;
			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ;
			}
			break ;

		case IDC_R_ALMAXORD: // select order of max. alignment
			if (IsDlgButtonChecked(hDlg,IDC_R_ALMAXORD) && _is.AlDataExist) 
			{
			    //VelsOff() ;
			   resorder = pAlFou->bigOrd ;				// derived from the Alignment spectrum over the AstGP
			resorderbud = BudGP * resorder / AstGP ;	// this is the component's order wrt the BudGP
                sprintf(buff,"%4.3f", resorder) ;
				SetDlgItemText(hDlg,IDC_E_RESORDER, buff) ;
                sprintf(buff,"%4.3f", resorderbud) ;
				SetDlgItemText(hDlg,IDC_E_RESORDERBUD, buff) ;
			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ;
			}
			break ;

		case IDC_R_DFLTORD:	 // select default order
			if (IsDlgButtonChecked(hDlg,IDC_R_DFLTORD))
			{
			    //VelsOff() ;
			   resorder = dfltresord ;
			resorderbud = BudGP * resorder / AstGP ;
                sprintf(buff,"%4.3f", resorder) ;
				SetDlgItemText(hDlg,IDC_E_RESORDER, buff) ;
                sprintf(buff,"%4.3f", resorderbud) ;
				SetDlgItemText(hDlg,IDC_E_RESORDERBUD, buff) ;
			EnableWindow(GetDlgItem(hDlg,IDOK), TRUE) ;
			}
			break ;

		case IDC_R_BPASS:
			wantNotch = 0 ;
			break ;

		case IDC_R_NOTCH:
			wantNotch = 1 ;
			break ;

		case IDC_R_TSUN:
			if (!_is.AllAlsExist) _is.AllAlsExist = All_Aligns(align->centre) ;
			break ;

		case IDC_R_TMER:
			if (!_is.AllAlsExist) _is.AllAlsExist = All_Aligns(align->centre) ;
			break ;

		case IDC_R_TVEN:
			if (!_is.AllAlsExist) _is.AllAlsExist = All_Aligns(align->centre) ;
			break ;

		case IDC_R_TMAR:
			if (!_is.AllAlsExist) _is.AllAlsExist = All_Aligns(align->centre) ;
			break ;

		case IDC_R_TJUP:
			if (!_is.AllAlsExist) _is.AllAlsExist = All_Aligns(align->centre) ;
			break ;

		case IDC_R_TSAT:
			if (!_is.AllAlsExist) _is.AllAlsExist = All_Aligns(align->centre) ;
			break ;

		case IDC_R_TURA:
			if (!_is.AllAlsExist) _is.AllAlsExist = All_Aligns(align->centre) ;
			break ;

		case IDC_R_TNEP:
			if (!_is.AllAlsExist) _is.AllAlsExist = All_Aligns(align->centre) ;
			break ;

		default:
			break ;
		}
		break ; // WM_COMMAND
	default:
		break ;
	} // switch( msg )
  return FALSE ;
} // TabTuned


BOOL CALLBACK TabSpectraDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	switch (msg)
	{
	case WM_INITDIALOG:
	OnChildDialogInit(hDlg) ;
		return TRUE ;

	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		case IDC_C_RASPC:  // the amplitude spectrum of the raw lambdas
			AmpliSpectrum = IsDlgButtonChecked(hDlg, IDC_C_RASPC) ;
		    SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_C_RSPC:   // the power spectrum of the raw lambdas
			PowerSpectrum = IsDlgButtonChecked(hDlg, IDC_C_RSPC) ;
		    SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_C_RPHA:   // the phase spectrum of the raw lambdas
			PlotPhase = IsDlgButtonChecked(hDlg, IDC_C_RPHA) ;
            SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_C_AL_POWER: // power spectrum of the alignment data
			PlotAlPow = IsDlgButtonChecked(hDlg, IDC_C_AL_POWER) ;
			SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_C_AL_AMPLITUDE: // amplitude spectrum of the alignment data
			PlotAlAmp = IsDlgButtonChecked(hDlg, IDC_C_AL_AMPLITUDE) ;
			if (PlotAlAmp) // enable the show/hide comps button
				EnableWindow(GetDlgItem(hDlg, IDC_AL_SINCOS),TRUE) ;
			else
			{
			    if (PlotSinCos) // if showing comps, turn them off
			       {
					PlotSinCos = 0 ;
				    CheckDlgButton(hDlg, IDC_AL_SINCOS, 0) ; // uncheck the button
				   }
				// disable the show/hide comps button
				EnableWindow(GetDlgItem(hDlg, IDC_AL_SINCOS),FALSE) ;
			}
			SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_AL_SINCOS:	// plot the sine and cosine fourier components
			PlotSinCos = IsDlgButtonChecked(hDlg, IDC_AL_SINCOS) ;
			SetFouFlags2() ;
			 updisp() ;
			 break ;

		case IDC_C_AL_PHASE: // phase spectrum of the alignment data
			PlotAlPha = IsDlgButtonChecked(hDlg, IDC_C_AL_PHASE) ;
			SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_C_MASPC:  // amplitude spectrum of running mean data
			mAmpliSpectrum = IsDlgButtonChecked(hDlg, IDC_C_MASPC) ;
			SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_C_MSPC:   // power spectrum of running mean data
			mPowerSpectrum = IsDlgButtonChecked(hDlg, IDC_C_MSPC) ;
			SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_C_MPHA:  // phase spectrum of running mean data
			mPlotPhase = IsDlgButtonChecked(hDlg, IDC_C_MPHA) ;
            SetFouFlags2() ;
			 updisp() ;
			break ;

		case IDC_C_ORDLINES: // the order lines corresponding to min, mean & max IAPs ("the 3 M's")
			Plot3MLines = IsDlgButtonChecked(hDlg, IDC_C_ORDLINES) ;
			SetFouFlags2() ;
			 updisp() ;
			break ;

		default:
			break ;
		} // switch(LOWORD(wParam))
		break ; // WM_COMMAND

	default:
		break ;
	} // switch (msg)

  return FALSE ;
} // TabSpectra


BOOL CALLBACK RasterisedDipsDlgProc( 
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static HWND hW ;
	static HWND E_ADV, U_ADV ;
	static Uflag ;

	char buff[40] ;

	switch (msg)
	{
	case WM_INITDIALOG:

		E_ADV = GetDlgItem(hDlg, IDC_E_ADVANCE) ;	// imposed shift edit box
		U_ADV = GetDlgItem(hDlg, IDC_U_ADVANCE) ;	// imposed shift U/D ctrl	

		SetUDRng(U_ADV, 3200, 0) ;
		SetUDPos(U_ADV,(int)(floor(100.0 * (leadlag + 16.0) / 32.0))) ;
		sprintf(buff, "%4.2f", leadlag) ;
		SetDlgItemText(hDlg, IDC_E_ADVANCE, buff) ;

		return TRUE ;

	case WM_HSCROLL:
		hW = (HWND)lParam ;

		if (hW == U_ADV)
		{
			int p ;
			p = GetUDPos(U_ADV) ;
			leadlag = 0.01 * (double)p - 16.0 ; 
			sprintf(buff, "%4.2f", leadlag) ;
			Uflag = 1 ;
			SetDlgItemText(hDlg, IDC_E_ADVANCE, buff) ;
		}
		break ;

	case WM_COMMAND:

		switch(HIWORD(wParam))
		{
		case EN_UPDATE:
			switch (LOWORD(wParam))
			{
			case IDC_E_ADVANCE:
				{
				char lead[40] ;
				GetDlgItemText(hDlg, IDC_E_ADVANCE, lead, 40) ;
				leadlag = atof(lead) ;
				if (!Uflag)
				SetUDPos(U_ADV,(int)(floor(100.0 * (leadlag + 16.0)))) ;
				if (Uflag) Uflag = 0 ;
				ivrc(hWndRast, NULL, TRUE) ;
				}
				break ;
			
			default:
				break ;
			}
			break ;

		default:
			break ;
		}

		switch(LOWORD(wParam))
		{

		case IDC_B_NO_ADVANCE:
			leadlag = 0.0 ;
			SetUDPos(U_ADV,(int)(floor(100.0 * (leadlag + 8.0)))) ;
			sprintf(buff, "%4.2f", leadlag) ;
			SetDlgItemText(hDlg, IDC_E_ADVANCE, buff) ;
			break ;

		case IDC_C_SYNTH_RAW_DIPS:
			RastRawDips = IsDlgButtonChecked(hDlg, IDC_C_SYNTH_RAW_DIPS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_SYNTH_MEAN_DIPS:
			RastMeanDips = IsDlgButtonChecked(hDlg, IDC_C_SYNTH_MEAN_DIPS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_SYNTH_RAW_PEAKS:
			RastRawPeaks = IsDlgButtonChecked(hDlg, IDC_C_SYNTH_RAW_PEAKS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_SYNTH_MEAN_PEAKS:
			RastMeanPeaks= IsDlgButtonChecked(hDlg, IDC_C_SYNTH_MEAN_PEAKS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_TUNED_RAW_DIPS:
			RastTunedRawDips = IsDlgButtonChecked(hDlg, IDC_C_TUNED_RAW_DIPS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_TUNED_MEAN_DIPS:
			RastTunedMeanDips = IsDlgButtonChecked(hDlg, IDC_C_TUNED_MEAN_DIPS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_TUNED_RAW_PEAKS:
			RastTunedRawPeaks = IsDlgButtonChecked(hDlg, IDC_C_TUNED_RAW_PEAKS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;

		case IDC_C_TUNED_MEAN_PEAKS:
			RastTunedMeanPeaks = IsDlgButtonChecked(hDlg, IDC_C_TUNED_MEAN_PEAKS) ;
			ivrc(hWndRast, NULL, TRUE) ;
			break ;


		default :
		break ;
		} // switch(LOWORD(wParam))

	default:
		break ; // WM_COMMAND
	} // switch (msg)

  return FALSE ;
} // RasterisedDipsDlgProc

BOOL CheckRastBodyList( void )
{
	int p ;
	for (p = MER ; p <= SUN ; p++)
	{
		if (p == PLU) continue ;
		if (RastBodyList[p]) return TRUE ;
	}
	return FALSE ;
}

// spill over from TabsystemicDlgProc().
// ran out of button room!
BOOL CALLBACK TabSystemicIIDlgProc( 
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static HWND hW, U_AS, U_MUL ;
	static char buff[20] ;
	static      TempVal, rtSpan, rmhold = 2000 ;
 //	  BOOL      snafu ;

	switch (msg)
	{
	case WM_INITDIALOG:

	CheckRadioButton(hDlg,
		IDC_R_GEO_DIRMEANB,
		IDC_R_HEL_DIRMEANB,
		IDC_R_HEL_DIRMEANB) ;

	SendMessage(GetDlgItem(hDlg, IDC_R_ACCDIR),BM_SETCHECK, BST_CHECKED, 0L) ;

	U_AS = GetDlgItem(hDlg, IDC_U_ASHIFT) ;
	SetUDRng(U_AS, 10000, 0) ;
	SetUDPos(U_AS, (int)(10.0 * ashift)) ;
	sprintf(buff, "%3.2f", ashift) ;
	SetDlgItemText(hDlg, IDC_E_ASHIFT, buff) ;

	U_MUL = GetDlgItem(hDlg, IDC_U_MULTIPLY) ;
	SetUDRng(U_MUL, 10000, 0) ;
	SetUDPos(U_MUL, (int)(10.0 * latiply)) ;
	sprintf(buff, "%3.2f", latiply) ;
	SetDlgItemText(hDlg, IDC_E_MULTIPLY, buff) ;

	OnChildDialogInit(hDlg) ;
		return TRUE ;

 	   case WM_VSCROLL:  // Service up/down controls
		   hW = (HWND)lParam ;
			if (hW == U_AS)
			{
				ashift = (double)GetUDPos(hW) / 10.0 ;
				sprintf(buff, "%3.2f", ashift) ;
				SetDlgItemText(hDlg, IDC_E_ASHIFT, buff) ;
			}

			{
				latiply = (double)GetUDPos(hW) / 10.0 ;
				sprintf(buff, "%3.2f", latiply) ;
				SetDlgItemText(hDlg, IDC_E_MULTIPLY, buff) ;
			}
			   break ;

	case WM_COMMAND:
		switch(LOWORD(wParam))
		{
		case IDC_E_ASHIFT:
				GetDlgItemText(hDlg, IDC_E_ASHIFT, buff, 20) ;
				ashift = atof(buff) ;
				SetUDPos(U_AS, (int)(10.0 * ashift)) ;
			break ;

		case IDC_E_MULTIPLY:
				GetDlgItemText(hDlg, IDC_E_MULTIPLY, buff, 20) ;
				latiply = atof(buff) ;
				SetUDPos(U_AS, (int)(10.0 * latiply)) ;
			break ;


		case IDC_R_GEO_DIRMEANB: // geocentric direction of mean body
        if (IsDlgButtonChecked(hDlg, IDC_R_GEO_DIRMEANB)) GeocMeanBod = 1 ;
		if (PlotDirMean) updisp() ;
			break ;

		case IDC_R_HEL_DIRMEANB: // heliocentric direction of mean body
        if (IsDlgButtonChecked(hDlg, IDC_R_HEL_DIRMEANB)) GeocMeanBod = 0 ;
		if (PlotDirMean) updisp() ;
			break ;

		case IDC_C_VECTOR_SUM: // magnitude of velocity vector on mean body 
		PlotVectorSum = IsDlgButtonChecked(hDlg, IDC_C_VECTOR_SUM) ;
		if (PlotVectorSum) VelsOn() ; updisp() ;
			break ;

		case IDC_C_VECTOR_DIR: // argument of velocity vector on mean body 
		PlotVectorDir = IsDlgButtonChecked(hDlg, IDC_C_VECTOR_DIR) ;
		if (PlotVectorDir) VelsOn() ; updisp() ;
			break ;

		case IDC_C_VECTOR_LAT: // argument of velocity vector on mean body 
		PlotVectorLat = IsDlgButtonChecked(hDlg, IDC_C_VECTOR_LAT) ;
		if (PlotVectorLat) VelsOn() ; updisp() ;
			break ;


		case IDC_C_ACCEL_SUM: // magnitude of acceleration vector on mean body 
		PlotAccelSum = IsDlgButtonChecked(hDlg, IDC_C_ACCEL_SUM) ;
		if (PlotAccelSum) VelsOn() ; else VelsOff() ; updisp() ;
			break ;

		case IDC_C_ACCEL_DIR: // argument of acceleration vector on mean body 
		PlotAccelDir = IsDlgButtonChecked(hDlg, IDC_C_ACCEL_DIR) ;
		if (PlotAccelDir) VelsOn() ; updisp() ;
			break ;

		case IDC_C_ACCEL_LAT: // latitude of acceleration vector on mean body 
		PlotAccelLat = IsDlgButtonChecked(hDlg, IDC_C_ACCEL_LAT) ;
		if (PlotAccelLat) VelsOn() ; updisp() ;
			break ;

		case IDC_C_COM_VECTOR_SUM: // magnitude of velocity vector on mass centre 
		PlotCoMVectorSum = IsDlgButtonChecked(hDlg, IDC_C_COM_VECTOR_SUM) ;
		if (PlotCoMVectorSum) VelsOn() ; updisp() ;
			break ;

		case IDC_C_COM_VECTOR_DIR: // argument of velocity vector on mass centre 
		PlotCoMVectorDir = IsDlgButtonChecked(hDlg, IDC_C_COM_VECTOR_DIR) ;
		if (PlotCoMVectorDir) VelsOn() ; updisp() ;
			break ;

		case IDC_C_COM_VECTOR_LAT: // latitude of velocity vector on mass centre 
		PlotCoMVectorLat = IsDlgButtonChecked(hDlg, IDC_C_COM_VECTOR_LAT) ;
		if (PlotCoMVectorLat) VelsOn() ; ; updisp() ;
			break ;


		case IDC_C_COM_ACCEL_SUM: // magnitude of acceleration vector on mass centre 
		PlotCoMAccelSum = IsDlgButtonChecked(hDlg, IDC_C_COM_ACCEL_SUM) ;
		if (PlotCoMAccelSum) VelsOn() ; updisp() ;
			break ;

		case IDC_C_COM_ACCEL_DIR: // argument of acceleration vector on mass centre 
		PlotCoMAccelDir = IsDlgButtonChecked(hDlg, IDC_C_COM_ACCEL_DIR) ;
		if (PlotCoMAccelDir) VelsOn() ;	
		updisp() ;
			break ;

		case IDC_C_COM_ACCEL_LAT: // argument of acceleration vector on mass centre 
		PlotCoMAccelLat = IsDlgButtonChecked(hDlg, IDC_C_COM_ACCEL_LAT) ;
		if (PlotCoMAccelLat) VelsOn() ;
		updisp() ;
			break ;

		case IDC_C_TEST: // testing launch 
		PlotTest = IsDlgButtonChecked(hDlg, IDC_C_TEST) ;
		if (PlotTest) VelsOn() ;
		updisp() ;
			break ;

		case IDC_C_TEST1: // testing launch 
		PlotTest1 = IsDlgButtonChecked(hDlg, IDC_C_TEST1) ;
		if (PlotTest1) VelsOn() ;
		updisp() ;
			break ;

		case IDC_C_TEST2: // testing launch 
		PlotTest2 = IsDlgButtonChecked(hDlg, IDC_C_TEST2) ;
		if (PlotTest2) VelsOn() ;
		updisp() ;
			break ;

		case IDC_R_VELDIR:
			PredictionModel = 0 ;
			   break ;

		case IDC_R_ACCDIR:
			PredictionModel = 1 ;
			   break ;

		case IDC_R_JUPDIR:
			PredictionModel = 2 ;
			   break ;

		case IDC_C_MB_HRADIUS: // heliocentric radius of mean body 
		PlotMBhRadius = IsDlgButtonChecked(hDlg, IDC_C_MB_HRADIUS) ;
			 updisp() ;
			break ;

		case IDC_C_DIRMEAN: // direction of mean body
			PlotDirMean = IsDlgButtonChecked(hDlg, IDC_C_DIRMEAN) ;
			 updisp() ;
			break ;

		default:
			break ;
		} // switch(LOWORD(wParam))
		break ; // WM_COMMAND

	default:
		break ;
	} // switch (msg)

  return FALSE ;
} // TabSystemicII

BOOL CALLBACK TabViewSettingsDlgProc(  
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	HWND hW ;
	static HWND UDViewRate, UDFieldRadius ;
	char bf[100] ;

	switch (msg)
	{
	case WM_INITDIALOG:

	   UDViewRate = GetDlgItem(hDlg,     IDC_U_VIEWRATE) ;
	UDFieldRadius = GetDlgItem(hDlg, IDC_U_FIELD_RADIUS) ;

	SetUDRng(UDViewRate, MAXVIEWRATE, 0) ;
	SetUDPos(UDViewRate, 9) ;
	SetUDRng(UDFieldRadius, 1000, 0) ;
	SetUDPos(UDFieldRadius, (int)(10.0 * FieldRadius)) ;
	sprintf(bf,"%3.2f", FieldRadius) ;
	SetDlgItemText(hDlg,IDC_E_FIELD_RADIUS, bf) ; 
	SetDlgItemInt( hDlg,IDC_E_VIEWRATE, ViewRate, FALSE) ;

	if (wantBodies)
		CheckDlgButton(hDlg, IDC_C_WANT_BODS, BST_CHECKED) ;
	else
		CheckDlgButton(hDlg, IDC_C_WANT_BODS, BST_UNCHECKED) ;

	if (wantMB)
		CheckDlgButton(hDlg, IDC_C_WANT_MEAN_BOD, BST_CHECKED) ;
	else
		CheckDlgButton(hDlg, IDC_C_WANT_MEAN_BOD, BST_UNCHECKED) ;

	if (wantMassCentre)
		CheckDlgButton(hDlg, IDC_C_WANT_MASS_CENTRE, BST_CHECKED) ;
	else
		CheckDlgButton(hDlg, IDC_C_WANT_MASS_CENTRE, BST_UNCHECKED) ;

	CheckRadioButton(hDlg,	IDC_R_TP_BYMASS,
							IDC_R_TP_BYPOS,
							IDC_R_TP_BYMASS) ;

	CheckRadioButton(hDlg,	IDC_R_WANT_CENTRE_ON_MBD,
							IDC_R_WANT_CENTRE_ON_NEP,
							IDC_R_WANT_CENTRE_ON_SUN) ;

	OnChildDialogInit(hDlg) ;
		return TRUE ;

 	   case WM_VSCROLL:  // Service up/down control

		   hW = (HWND)lParam ;

		   if (hW == UDFieldRadius)
		   {
			   FieldRadius = 0.1 * (double)GetUDPos(UDFieldRadius) ;
			   sprintf(bf,"%3.2f", FieldRadius) ;
			   SetDlgItemText(hDlg, IDC_E_FIELD_RADIUS, bf) ;
		   }
			   break ;

	case WM_COMMAND:

		switch(LOWORD(wParam))
		{
		case IDC_C_VIEWER:
			{
				 static RECT drc, arc ;
				       POINT pt ;
			if (IsDlgButtonChecked(hDlg, IDC_C_VIEWER))
			{
			// If the viewer window does not exist, make it now.
			if (hWndView == (HWND)NULL)  
		  hWndView = CreateWindow("ViewNodal",
			                      "Viewer",
	                               WS_CHILD|WS_CLIPSIBLINGS|
		                           WS_CAPTION|WS_SIZEBOX|
		                           WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
		                           WS_SYSMENU,                    
								   (rcctrl.right - rcctrl.left)/2,
								   45,
								   (rcctrl.right - rcctrl.left)/2,
								   (rcctrl.bottom - rcctrl.top) - 45,
								   hWndCtrl,
								   NULL,
								   hInst,
								   NULL
								  ) ;

			// Get and convert the current Archive Window Rect
				GetWindowRect(hWndArch, &arc) ;
				pt.x = arc.left ;
				pt.y = arc.top ;
				ScreenToClient(hWndCtrl, &pt) ;
				arc.left = pt.x ;
				arc.top  = pt.y ;
				pt.x = arc.right ;
				pt.y = arc.bottom ;
				ScreenToClient(hWndCtrl, &pt) ;
				arc.right  = pt.x ;
				arc.bottom = pt.y ;

			// The dialog box calling for this must be showing.
			// Move it to the top left, and get its dimensions.

				SetWindowPos(hPanelDlg, HWND_TOP,
								0,0,0,0,
								SWP_NOSIZE) ;
				GetWindowRect(hPanelDlg, &drc) ;

			// Move the Viewer to the right of the Dialog Box.
				SetWindowPos(hWndView, HWND_TOP,
					         rcctrl.left + (drc.right - drc.left),	// new x
							 45,									// new y, same as old
							(rcctrl.right - rcctrl.left) - (drc.right - drc.left), // new width
							(rcctrl.bottom - rcctrl.top) - 45,		// new height, same as old
							 SWP_SHOWWINDOW) ;

			// Move the Archive chart to left of the Viewer
				SetWindowPos(hWndArch, HWND_TOP,
					arc.left,				// same x as old
					arc.top,				// same y as old
					drc.right - drc.left,	// same width as the Dialog Box
					arc.bottom - arc.top,	// same height as old
					SWP_SHOWWINDOW) ;
			}
			else // Hide the viewer, and restore the Archive chart
			{
				ShowWindow(hWndView, SW_HIDE) ;
				SetWindowPos(hWndArch, HWND_TOP,
					arc.left,
					arc.top,
					arc.right - arc.left,
					arc.bottom - arc.top,
					SWP_SHOWWINDOW) ;
				// we are turning off, so set the viewcount to zero
					viewcount = 0 ;
			}
			}
			break ;

		case IDC_C_VIEWER_BKDROP:		// Black or Gray background
			wantBackdrop = IsDlgButtonChecked(hDlg, IDC_C_VIEWER_BKDROP) ;
			break ;

		case IDC_C_WANT_BODS:			// Show the Selected Bodies
			wantBodies = IsDlgButtonChecked(hDlg, IDC_C_WANT_BODS) ;
			break ;

		case IDC_C_WANT_MEAN_BOD:		// Show the Mean Body
			wantMB = IsDlgButtonChecked(hDlg, IDC_C_WANT_MEAN_BOD) ;
			break ;

		case IDC_C_WANT_MASS_CENTRE:	// Show the Mass Centre
			wantMassCentre = IsDlgButtonChecked(hDlg, IDC_C_WANT_MASS_CENTRE) ;
			break ;

		case IDC_C_WANT_MB_HELIOC_DIR:	// Heliocentric direction of mean body
			wantHeliocDirofMB = IsDlgButtonChecked(hDlg, IDC_C_WANT_MB_HELIOC_DIR) ; 
			break ;

		case IDC_C_EXT_SUN_TO_MB:		// Extended Heliocentric direction of Mean body
			wantExtSunToMB = IsDlgButtonChecked(hDlg, IDC_C_EXT_SUN_TO_MB) ;
			break ;

		case IDC_C_WANT_MB_GEOC_DIR:	// Geocentric direction of mean body
			wantGeocDirofMB = IsDlgButtonChecked(hDlg, IDC_C_WANT_MB_GEOC_DIR) ; 
			break ;

		case IDC_C_WANT_MASS_HELIOC_DIR:	// Heliocentric direction of mass centre
			wantHeliocDirofMass = IsDlgButtonChecked(hDlg, IDC_C_WANT_MASS_HELIOC_DIR) ; 
			break ;

		case IDC_C_WANT_MASS_GEOC_DIR:	// Geocentric direction of mass centre
			wantGeocDirofMass = IsDlgButtonChecked(hDlg, IDC_C_WANT_MASS_GEOC_DIR) ; 
			break ;



		case IDC_C_WANT_INTER_BODY_LINES:	// Inter body connecting lines
			wantInterbodyLines = IsDlgButtonChecked(hDlg, IDC_C_WANT_INTER_BODY_LINES) ; 
			break ;

		case IDC_C_WANT_MEAN_BODY_LINES:	// Connecting lines from mean body to bodies
			wantMeanbodyLines = IsDlgButtonChecked(hDlg, IDC_C_WANT_MEAN_BODY_LINES) ; 
			break ;

		case IDC_C_WANT_MASS_CENTRE_LINES:	// Connecting lines from Mass Centre to bodies
			wantCoMLines = IsDlgButtonChecked(hDlg, IDC_C_WANT_MASS_CENTRE_LINES) ; 
			break ;

		case IDC_C_MB_VEL_VECTOR:	// show Velocity vector of mean body
			wantMBvelVect = IsDlgButtonChecked(hDlg, IDC_C_MB_VEL_VECTOR) ; 
			break ;

		case IDC_C_MB_VEL_VEC_ENDPOINT:	// show end point of Velocity vector of mean body
			wantMBvelEndPt = IsDlgButtonChecked(hDlg, IDC_C_MB_VEL_VEC_ENDPOINT) ; 
			break ;

		case IDC_C_MB_ACC_VECTOR:	// show Acceleration vector of mean body
			wantMBaccVect = IsDlgButtonChecked(hDlg, IDC_C_MB_ACC_VECTOR) ; 
			break ;

		case IDC_C_MB_ACC_VEC_ENDPOINT:	// show end point of Acceleration vector of mean body
			wantMBaccEndPt = IsDlgButtonChecked(hDlg, IDC_C_MB_ACC_VEC_ENDPOINT) ; 
			break ;

		case IDC_C_COM_VEL_VECTOR:	// show Velocity vector of centre of mass
			wantCoMvelVect = IsDlgButtonChecked(hDlg, IDC_C_COM_VEL_VECTOR) ; 
			break ;

		case IDC_C_EXT_VEL:	// Extend Velocity vector of centre of mass
			wantExtVelVect = IsDlgButtonChecked(hDlg, IDC_C_EXT_VEL) ; 
			break ;

		case IDC_C_COM_VEL_VEC_ENDPOINT:	// show end point of Velocity vector of centre of mass
			wantCoMvelEndPt = IsDlgButtonChecked(hDlg, IDC_C_COM_VEL_VEC_ENDPOINT) ; 
			break ;

		case IDC_C_COM_ACC_VECTOR:	// show Acceleration vector of centre of mass
			wantCoMaccVect = IsDlgButtonChecked(hDlg, IDC_C_COM_ACC_VECTOR) ; 
			break ;

		case IDC_C_ACC_VECT_SUN:	// show Acceleration vector of centre of mass
			wantCoMaccVectinSun = IsDlgButtonChecked(hDlg, IDC_C_ACC_VECT_SUN) ; 
			break ;

		case IDC_C_EXT_ACC:	// Extend Acceleration vector of centre of mass
			wantExtAccVect = IsDlgButtonChecked(hDlg, IDC_C_EXT_ACC) ; 
			break ;

		case IDC_C_EXT_ACC2:	// Extend Acceleration vector in Sun
			wantExtAccVectSun = IsDlgButtonChecked(hDlg, IDC_C_EXT_ACC2) ; 
			break ;

		case IDC_C_COM_ACC_VEC_ENDPOINT:	// show end point of Acceleration vector of centre of mass
			wantCoMaccEndPt = IsDlgButtonChecked(hDlg, IDC_C_COM_ACC_VEC_ENDPOINT) ; 
			break ;

		case IDC_C_WANT_IBODY_TPS: // Inter-Body Turning Points
			 wantInterbodyTPs = IsDlgButtonChecked(hDlg, IDC_C_WANT_IBODY_TPS) ;
			if (wantInterbodyTPs) VelsOn() ;
			break ;

		case IDC_C_SYSTEMIC_PRIMARY:	// 'Systemic Primary'
			wantSystemicPrimary = IsDlgButtonChecked(hDlg, IDC_C_SYSTEMIC_PRIMARY) ; 
			if (wantSystemicPrimary) VelsOn() ;
			break ;

		case IDC_R_TP_BYMASS: // Turning points of Systemic Lines by mass
			wantTPbyMass = 1 ;
			break ;

		case IDC_R_TP_BYPOS: // Turning points of Systemic Lines by position
			wantTPbyMass = 0 ;
			break ;

		case IDC_R_WANT_CENTRE_ON_MBD:	// Viewer Centre on Mean Body
			ViewCentre = MBD ;
			break ;

		case IDC_R_WANT_CENTRE_ON_MAS: // Viewer Centre on Mass Centre
			ViewCentre = MAS ;
			break ;


		case IDC_R_WANT_CENTRE_ON_SUN:	// Viewer Centre on Sun
			ViewCentre = SUN ;
			break ;

		case IDC_R_WANT_CENTRE_ON_EAR:	// Viewer Centre on Earth
			ViewCentre = EAR ;
			break ;

		case IDC_R_WANT_CENTRE_ON_MOO:	// Viewer Centre on Moon
			ViewCentre = MOO ;
			break ;

		case IDC_R_WANT_CENTRE_ON_MER:	// Viewer Centre on Mercury
			ViewCentre = MER ;
			break ;

		case IDC_R_WANT_CENTRE_ON_VEN:	// Viewer Centre on Venus
			ViewCentre = VEN ;
			break ;

		case IDC_R_WANT_CENTRE_ON_MAR:	// Viewer Centre on Mars
			ViewCentre = MAR ;
			break ;

		case IDC_R_WANT_CENTRE_ON_JUP:	// Viewer Centre on Jupiter
			ViewCentre = JUP ;
			break ;

		case IDC_R_WANT_CENTRE_ON_SAT:	// Viewer Centre on Saturn
			ViewCentre = SAT ;
			break ;

		case IDC_R_WANT_CENTRE_ON_URA:	// Viewer Centre on Uranus
			ViewCentre = URA ;
			break ;

		case IDC_R_WANT_CENTRE_ON_NEP:	// Viewer Centre on Neptune
			ViewCentre = NEP ;
			break ;

		case IDC_E_VIEWRATE:		// Adjust rate of animation
			{
				BOOL snafu ;
				UINT value ;
			    value = GetDlgItemInt(hDlg, IDC_E_VIEWRATE, &snafu, FALSE) ;
				ViewRate = MAXVIEWRATE - value + 1;
			}
			break ;

		case IDC_E_FIELD_RADIUS:	// Adjust radius of View Field
			    GetDlgItemText(hDlg, IDC_E_FIELD_RADIUS, bf, 100) ;
				FieldRadius = atof(bf) ;
				SetUDPos(UDFieldRadius, (int)(10.0 * FieldRadius)) ;
			break ;

		case IDC_C_DATE_MOUSED:
			wantMousedEp = IsDlgButtonChecked(hDlg, IDC_C_DATE_MOUSED) ;
			if (wantMousedEp)
			{
					CheckDlgButton(hDlg, IDC_C_ENABLE_OPS, BST_UNCHECKED) ;
					OpsViewEnable = IsDlgButtonChecked(hDlg, IDC_C_ENABLE_OPS) ;
					EnableWindow(GetDlgItem(hDlg, IDC_C_ENABLE_OPS), FALSE) ;
					CheckDlgButton(hDlg, IDC_C_DATE_CLICK, BST_UNCHECKED) ;
					EnableWindow(GetDlgItem(hDlg, IDC_C_DATE_CLICK), FALSE) ;
					OpsViewEnable = 1 ;  wantDateClick = 0 ;

			}
			else
			{
					EnableWindow(GetDlgItem(hDlg, IDC_C_ENABLE_OPS), TRUE) ;
					OpsViewEnable = IsDlgButtonChecked(hDlg, IDC_C_ENABLE_OPS) ;
					EnableWindow(GetDlgItem(hDlg, IDC_C_DATE_CLICK), TRUE) ;
			}

			break ;

		case IDC_C_DATE_CLICK:		// Enable Click on Date
			wantDateClick = IsDlgButtonChecked(hDlg, IDC_C_DATE_CLICK) ;
			if (wantDateClick)
			{
				CheckDlgButton(hDlg, IDC_C_ENABLE_OPS,  BST_UNCHECKED) ;
				CheckDlgButton(hDlg, IDC_C_DATE_MOUSED, BST_UNCHECKED) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DATE_MOUSED), FALSE) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ENABLE_OPS), FALSE) ;
				OpsViewEnable = 1 ; wantMousedEp = 0 ;
			}
			else
			{
				EnableWindow(GetDlgItem(hDlg, IDC_C_ENABLE_OPS), TRUE) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_DATE_MOUSED), TRUE) ;
				EnableWindow(GetDlgItem(hDlg, IDC_C_ENABLE_OPS), TRUE) ;
			    OpsViewEnable = IsDlgButtonChecked(hDlg, IDC_C_ENABLE_OPS) ;
			}
			break ;

		case IDC_C_ENABLE_OPS:		// View whole selected period
			OpsViewEnable = IsDlgButtonChecked(hDlg, IDC_C_ENABLE_OPS) ;

			if (OpsViewEnable)
			{
				viewcount = 0 ; updisp() ;

			}
			break ;

		default:
			break ;
		} // switch(LOWORD(wParam))
		break ; // WM_COMMAND

	default:
		break ;
	} // switch (msg)

  return FALSE ;
} // TabViewSettings

int updisp( void )
{

	   			ShowLambdaScale = ( PlotData   ||
									PlotSynth  ||
									mPlotData  ||
									mPlotSynth ||
									PlotFSynth ||
									mPlotFSynth||
									PlotComp   ||
									mPlotComp ) ? 1 : 0 ;

	if (GoForIt)
		ivrc(hWndArch, NULL, TRUE) ;

	return 1 ;

}

// though it works somewhat, the
// date setting method is silly. FIX!!!
int checkeps( void ) 
{
	int i ;

	for ( i = 0, st.Ep1Set = 1 ; i < 6 ; i++ )
		if (!st.Set[i]) st.Ep1Set = 0 ;
	for ( i = 6, st.Ep2Set = 1 ; i < 12 ; i++ )

		if (!st.Set[i]) st.Ep2Set = 0 ;
		{
		st.AllEpSet = 1 ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_VECTOR_SUM),	TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_VECTOR_DIR),	TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_VECTOR_LAT),	TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_ACCEL_SUM),	TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_ACCEL_DIR),	TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_ACCEL_LAT),	TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_VECTOR_SUM),		TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_VECTOR_DIR),		TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_VECTOR_LAT),		TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_ACCEL_SUM),		TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_ACCEL_DIR),		TRUE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_ACCEL_LAT),		TRUE) ;
		}

	if (!st.Ep1Set || !st.Ep2Set)
		{
		st.AllEpSet = 0 ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_VECTOR_SUM),	FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_VECTOR_DIR),	FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_VECTOR_LAT),	FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_ACCEL_SUM),	FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_ACCEL_DIR),	FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_COM_ACCEL_LAT),	FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_VECTOR_SUM),		FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_VECTOR_DIR),		FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_VECTOR_LAT),		FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_ACCEL_SUM),		FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_ACCEL_DIR),		FALSE) ;
		EnableWindow(GetDlgItem(hDlgSystemicII, IDC_C_ACCEL_LAT),		FALSE) ;
		}

	return st.AllEpSet ;
}


void SetTimeFlags2( void )
{
	// Set time-series flag,
	// and reset all currently
	// asserted frequency-domain
	// controls and displays.

			 st.TimeSeries = 1 ;

			 PowerSpectrum = 0 ;
			mPowerSpectrum = 0 ;
			 AmpliSpectrum = 0 ;
			mAmpliSpectrum = 0 ;
			     PlotPhase = 0 ;
			    mPlotPhase = 0 ;
				PlotAgraph = 0 ;
			   mPlotAgraph = 0 ;
			   LPlotSynAgr = 0 ;
			  mLPlotSynAgr = 0 ;
			     PlotAlPow = 0 ;
				 PlotAlAmp = 0 ;
			     PlotAlPha = 0 ;
				PlotSinCos = 0 ;

			   Plot3MLines = 0 ;

			CheckDlgButton(hDlgDisplay, IDC_C_RAGR,           0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MAGR,           0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_RAGR_SYNTHETIC, 0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MAGR_SYNTHETIC, 0) ;

			CheckDlgButton(hDlgSpectra, IDC_C_RSPC,          0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_RASPC,         0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_MSPC,          0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_MASPC,         0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_RPHA,          0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_MPHA,          0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_AL_POWER,      0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_AL_AMPLITUDE,  0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_AL_PHASE,      0) ;
			CheckDlgButton(hDlgSpectra, IDC_AL_SINCOS,       0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_IMP_POWER,     0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_IMP_AMPLITUDE, 0) ;
			CheckDlgButton(hDlgSpectra, IDC_C_IMP_PHASE,     0) ;

			CheckDlgButton(hDlgSpectra, IDC_C_ORDLINES,      0) ;
}

void SetFouFlags2( void )
{
	// Reset time-series flag,
	// and currently asserted
	// time-domain controls and
	// displays.

		    st.TimeSeries = 0 ;
	   DegreeScaleShowing = 0 ;
	AlignmentScaleShowing = 0 ;
	     DaysScaleShowing = 0 ;

			     PlotData = 0 ;
			    mPlotData = 0 ;
			    PlotSynth = 0 ;
		 	   mPlotSynth = 0 ;
			   PlotFSynth = 0 ;
			  mPlotFSynth = 0 ;
			     PlotComp = 0 ;
			    mPlotComp = 0 ;
			   PlotShifts = 0 ;
		      mPlotShifts = 0 ;

			   PlotAgraph = 0 ;
		      mPlotAgraph = 0 ;
			  LPlotSynAgr = 0 ;
			 mLPlotSynAgr = 0 ;

			  PlotSysPeri = 0 ;
			PlotBSysAlign = 0 ;
			  PlotSelLong = 0 ;
			    PlotNEqLo = 0 ;
			    PlotNEcLo = 0 ;
			   PlotPeriLo = 0 ;
			      PlotMot = 0 ;
			     PlotAMot = 0 ;
			   PlotAlData = 0 ;
			    PlotCRate = 0 ;
				PlotSysAV = 0 ;
			  PlotAlSysAV = 0 ;
			  PlotCsqRate = 0 ;

			  PlotDirMean = 0 ;
		   PlotSysDirMean = 0 ;
		     PlothMassDir = 0 ;

			PlotVectorSum = 0 ;
			PlotVectorDir = 0 ;
			 PlotAccelSum = 0 ;
			 PlotAccelDir = 0 ;

		  PlotSysDirOnSun = 0 ;
		   PlotSysAlOnSun = 0 ;
		     PlotObsShift = 0 ;

			 LPlotSynTune = 0 ;
			mLPlotSynTune = 0 ;

			   RastRawDips = 0 ;
              RastMeanDips = 0 ;
              RastRawPeaks = 0 ;
             RastMeanPeaks = 0 ;
          RastTunedRawDips = 0 ;
		 RastTunedMeanDips = 0 ;
		 RastTunedRawPeaks = 0 ;
		RastTunedMeanPeaks = 0 ;

			CheckDlgButton(hDlgTuned, IDC_C_TUNE_RAW_LAMBDA,       0) ;
			CheckDlgButton(hDlgTuned, IDC_C_TUNE_MEAN_LAMBDA,      0) ;

			CheckDlgButton(hDlgSystemicII, IDC_C_DIRMEAN,          0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_VECTOR_SUM,       0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_VECTOR_DIR,       0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_ACCEL_SUM,        0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_ACCEL_DIR,        0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_SYSDIRMEAN,       0) ;

			CheckDlgButton(hRastDlg, IDC_C_SYNTH_RAW_DIPS,   0) ;
			CheckDlgButton(hRastDlg, IDC_C_SYNTH_MEAN_DIPS,  0) ;
			CheckDlgButton(hRastDlg, IDC_C_TUNED_RAW_DIPS,   0) ;
			CheckDlgButton(hRastDlg, IDC_C_TUNED_MEAN_DIPS,  0) ;
			CheckDlgButton(hRastDlg, IDC_C_SYNTH_RAW_PEAKS,  0) ;
			CheckDlgButton(hRastDlg, IDC_C_SYNTH_MEAN_PEAKS, 0) ;
			CheckDlgButton(hRastDlg, IDC_C_TUNED_RAW_PEAKS,  0) ;
			CheckDlgButton(hRastDlg, IDC_C_TUNED_MEAN_PEAKS, 0) ;

			CheckDlgButton(hDlgMisc, IDC_C_FRACTION,		 0) ;
			CheckDlgButton(hDlgMisc, IDC_C_INODAL,           0) ;
			CheckDlgButton(hDlgMisc, IDC_C_EQN,              0) ;
			CheckDlgButton(hDlgMisc, IDC_C_PERI,             0) ;
			CheckDlgButton(hDlgMisc, IDC_C_MOT,              0) ;
			CheckDlgButton(hDlgMisc, IDC_C_AMOT,             0) ;
			CheckDlgButton(hDlgSystemic, IDC_C_SYSLONG,       0) ;
			CheckDlgButton(hDlgSystemic, IDC_C_SEL_LONG,      0) ;
			CheckDlgButton(hDlgSystemic, IDC_C_LEQ,           0) ;

			CheckDlgButton(hDlgDisplay, IDC_C_RDAT,           0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MDAT,           0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_RSYN,           0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MSYN,           0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_RFSYNTH,        0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_MFSYNTH,        0) ;
			CheckDlgButton(hDlgDisplay, IDC_C_RCMP,           0) ; // raw component
			CheckDlgButton(hDlgDisplay, IDC_C_MCMP,           0) ; // mean component
			CheckDlgButton(hDlgDisplay, IDC_C_RSHF,           0) ; // raw time shift
			CheckDlgButton(hDlgDisplay, IDC_C_MSHF,           0) ; // mean time shift
			CheckDlgButton(hDlgDisplay, IDC_C_RAGR,           0) ; // raw agraph
			CheckDlgButton(hDlgDisplay, IDC_C_MAGR,           0) ; // mean agraph
			CheckDlgButton(hDlgDisplay, IDC_C_ALGRAPH,        0) ; // cos^2 alignment
			CheckDlgButton(hDlgDisplay, IDC_C_AVEL,           0) ; // angular velocity difference
			CheckDlgButton(hDlgDisplay, IDC_C_CSQRATE,        0) ; // dee cos^2 by dee t
			CheckDlgButton(hDlgDisplay, IDC_C_PHASES,         0) ; // observed phase shift
			CheckDlgButton(hDlgDisplay, IDC_C_RAGR,           0) ; // raw  direct    agraph
			CheckDlgButton(hDlgDisplay, IDC_C_MAGR,           0) ; // mean direct    agraph
			CheckDlgButton(hDlgDisplay, IDC_C_RAGR_SYNTHETIC, 0) ; // raw  synthetic agraph
			CheckDlgButton(hDlgDisplay, IDC_C_MAGR_SYNTHETIC, 0) ; // mean synthetic agraph
}

void SetAgrFlags2( void )
{
	// Reset time-series flag
	// and currently asserted
	// time-domain and frequency-domain
	// controls and displays.

		     st.TimeSeries = 0 ;
	    DegreeScaleShowing = 0 ;
	 AlignmentScaleShowing = 0 ;

			    PlotAligns = 0 ;
			 PowerSpectrum = 0 ;
			mPowerSpectrum = 0 ;
			 AmpliSpectrum = 0 ;
			mAmpliSpectrum = 0 ;
			     PlotPhase = 0 ;
			    mPlotPhase = 0 ;
			      PlotData = 0 ;
			     mPlotData = 0 ;
			     PlotSynth = 0 ;
			    mPlotSynth = 0 ;
			    PlotFSynth = 0 ;
			   mPlotFSynth = 0 ;
			  PlotFAlSynth = 0 ;
			      PlotComp = 0 ;
			     mPlotComp = 0 ;
			    PlotShifts = 0 ;
		       mPlotShifts = 0 ;
			   PlotSysPeri = 0 ;
			 PlotBSysAlign = 0 ;
			   PlotSelLong = 0 ;
			     PlotNEqLo = 0 ;
			     PlotNEcLo = 0 ;
			    PlotPeriLo = 0 ;
			       PlotMot = 0 ;
			      PlotAMot = 0 ;
			    PlotAlData = 0 ;
				 PlotCRate = 0 ;
				 PlotSysAV = 0 ;
			   PlotAlSysAV = 0 ;
			   PlotCsqRate = 0 ;
		      PlotObsShift = 0 ;

			     PlotAlPow = 0 ;
				 PlotAlAmp = 0 ;
			     PlotAlPha = 0 ;
				PlotSinCos = 0 ;

			   Plot3MLines = 0 ;

			   PlotDirMean = 0 ;
			  PlothMassDir = 0 ;
			PlotSysDirMean = 0 ;
		   PlotSysDirOnSun = 0 ;
		    PlotSysAlOnSun = 0 ;
			 PlotVectorSum = 0 ;
			 PlotVectorDir = 0 ;
			  PlotAccelSum = 0 ;
			  PlotAccelDir = 0 ;
			  LPlotSynTune = 0 ;
			 mLPlotSynTune = 0 ;
			   RastRawDips = 0 ;
              RastMeanDips = 0 ;
              RastRawPeaks = 0 ;
             RastMeanPeaks = 0 ;
          RastTunedRawDips = 0 ;
		 RastTunedMeanDips = 0 ;
		 RastTunedRawPeaks = 0 ;
		RastTunedMeanPeaks = 0 ;

			CheckDlgButton(hDlgTuned,	   IDC_C_TUNE_RAW_LAMBDA,  0) ;
			CheckDlgButton(hDlgTuned,	   IDC_C_TUNE_MEAN_LAMBDA, 0) ;

			CheckDlgButton(hDlgSystemicII, IDC_C_SYSDIRMEAN,       0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_VECTOR_SUM,       0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_VECTOR_DIR,       0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_ACCEL_SUM,        0) ;
			CheckDlgButton(hDlgSystemicII, IDC_C_ACCEL_DIR,        0) ;

			CheckDlgButton(hRastDlg,	   IDC_C_SYNTH_RAW_DIPS,   0) ;
			CheckDlgButton(hRastDlg,	   IDC_C_SYNTH_MEAN_DIPS,  0) ;
			CheckDlgButton(hRastDlg,	   IDC_C_TUNED_RAW_DIPS,   0) ;
			CheckDlgButton(hRastDlg,	   IDC_C_TUNED_MEAN_DIPS,  0) ;
			CheckDlgButton(hRastDlg,	   IDC_C_SYNTH_RAW_PEAKS,  0) ;
			CheckDlgButton(hRastDlg,	   IDC_C_SYNTH_MEAN_PEAKS, 0) ;
			CheckDlgButton(hRastDlg,	   IDC_C_TUNED_RAW_PEAKS,  0) ;
			CheckDlgButton(hRastDlg,	   IDC_C_TUNED_MEAN_PEAKS, 0) ;

			CheckDlgButton(hDlgMisc,	   IDC_C_FRACTION,		   0) ;
			CheckDlgButton(hDlgMisc,	   IDC_C_INODAL,           0) ;
			CheckDlgButton(hDlgMisc,	   IDC_C_EQN,              0) ;
			CheckDlgButton(hDlgMisc,	   IDC_C_LEQ,              0) ;
			CheckDlgButton(hDlgMisc,	   IDC_C_PERI,             0) ;
			CheckDlgButton(hDlgMisc,	   IDC_C_MOT,              0) ;
			CheckDlgButton(hDlgMisc,	   IDC_C_AMOT,			   0) ;

			CheckDlgButton(hDlgSystemic,   IDC_C_SYSLONG,          0) ;
			CheckDlgButton(hDlgSystemic,   IDC_C_SEL_LONG,         0) ;

			CheckDlgButton(hDlgDisplay,    IDC_C_RDAT,			   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_MDAT,			   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_RSYN,			   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_MSYN,			   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_RFSYNTH,		   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_MFSYNTH,		   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_RCMP,			   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_MCMP,			   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_RSHF,			   0) ;
			CheckDlgButton(hDlgDisplay,    IDC_C_MSHF,			   0) ;
			CheckDlgButton(hDlgDisplay,		IDC_C_AVEL,			   0) ;
			CheckDlgButton(hDlgDisplay,		IDC_C_CSQRATE,		   0) ;
			CheckDlgButton(hDlgDisplay,		IDC_C_PHASES,		   0) ;
			CheckDlgButton(hDlgDisplay,		IDC_C_ALIG,			   0) ;

			CheckDlgButton(hDlgSpectra,		IDC_C_RSPC,          0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_MSPC,          0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_RASPC,         0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_MASPC,         0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_RPHA,          0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_MPHA,          0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_AL_POWER,      0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_AL_AMPLITUDE,  0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_AL_PHASE,      0) ;
			CheckDlgButton(hDlgSpectra,		IDC_AL_SINCOS,       0) ;
			CheckDlgButton(hDlgSpectra,		IDC_C_ORDLINES,		 0) ;
}

void ShowArchBar(HWND hWnd, char * buff)
{
			strcpy(szArchWindowTit, szArchWindowTxt) ;
			strcat(szArchWindowTit, " ") ;
			strcat(szArchWindowTit, buff) ;
			SetWindowText(hWnd, szArchWindowTit) ;
}

void RestoreExclusions( void )
{
	int i ;
	for ( i = 1 ; i <= MAXLEVELS ; IncludeLev[i++] = 1 ) ;
}

//**********************************************
//  Set Number of Measurement Heights on the Bud
//**********************************************
BOOL CALLBACK HytDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	static BOOL B, isOK ;
	static HWND hW, UDHyts, EDHyts ;
	static HWND UDFirstHyt, EDFirstHyt, BNFirstHyt, STFirstHyt ;
	static OldLevels ;
	  char buff[20] ;
	   int levs ;

	switch (msg)
	{
       case WM_INITDIALOG:

		   OldLevels = Levels ;

		       UDHyts = GetDlgItem(hDlg,IDC_SPIN_HEIGHTS) ;
		       EDHyts = GetDlgItem(hDlg,IDC_EDIT_HEIGHTS) ;
		   UDFirstHyt = GetDlgItem(hDlg,IDC_U_FIRSTHEIGHT) ;
		   EDFirstHyt = GetDlgItem(hDlg,IDC_E_FIRSTHEIGHT) ;
		   STFirstHyt = GetDlgItem(hDlg,IDC_S_FIRSTHEIGHT) ;
		   BNFirstHyt = GetDlgItem(hDlg,IDC_B_DEF_FIRSTHEIGHT) ;



	       SetUDRng(UDHyts,     MAXLEVELS, 3) ;
	       SetUDPos(UDHyts,     Levels) ;
		   SetUDRng(UDFirstHyt, 500, 0) ;

		   B = (GrowthMeasure) ? TRUE : FALSE ;

				 EnableWindow(EDFirstHyt, B) ;
				 EnableWindow(UDFirstHyt, B) ;
				 EnableWindow(BNFirstHyt, B) ;
				 EnableWindow(STFirstHyt, B) ;


		   CheckDlgButton(hDlg, IDC_C_GROWTH, GrowthMeasure) ;

		   if (UsingDefault)
		   FirstFrac = 1.0 / (double)Levels ;

		   SetUDPos(UDFirstHyt,(int)(1000.0 * FirstFrac)) ;
		   sprintf(buff,"%4.3f", FirstFrac) ;
		   SetDlgItemText(hDlg, IDC_E_FIRSTHEIGHT, buff) ;

		   return TRUE ;
		   break ;

	   case WM_VSCROLL:

	    hW = (HWND)lParam ;

			if (hW == UDHyts)
			{

				SendMessage
				   (
					EDHyts,
					WM_GETTEXT,
					20,
				   (LPARAM)buff
				   ) ;

				levs = atoi(buff) ;

				if (!(levs % 2)) // if levs is even
				{
					if (levs > Levels)   // we're going up.
					{
					 Levels = levs + 1 ; // so one more
					}
					else
					if (levs < Levels)   // we're going down.
					{
					 Levels = levs - 1 ; // so one less
					}
				}
				else                    // levs is already odd -- it's OK.
					Levels = levs ;

		pBudResults->NumHyts = Levels ;
		SetDlgItemInt(hDlg, IDC_EDIT_HEIGHTS, Levels, TRUE) ;
			}

		if (hW == UDFirstHyt)
			{
			 FirstFrac = 0.001 * (double)GetUDPos(UDFirstHyt) ;
			 sprintf(buff,"%4.3f", FirstFrac) ;
			 SetDlgItemText(hDlg, IDC_E_FIRSTHEIGHT, buff) ;
		    }

		   break ; // WM_VSCROLL

	   case WM_PARENTNOTIFY:
		   break ;

	   case WM_COMMAND:
		   switch(LOWORD(wParam))
		   {
		   case IDC_DEF_HEIGHTS:

		pBudResults->NumHyts = Levels = dfault ;
		SetDlgItemInt(hDlg,IDC_EDIT_HEIGHTS,Levels,TRUE) ;
		RestoreExclusions() ;
		EndDialog(hDlg, IDOK) ;	// quit dialogue at once

			   break ;

		   case IDC_C_GROWTH:

			     GrowthMeasure = IsDlgButtonChecked(hDlg, IDC_C_GROWTH) ;

				 // enable/disable controls
				   B = (GrowthMeasure) ? TRUE : FALSE ;

				   EnableWindow(EDFirstHyt, B) ;
				   EnableWindow(UDFirstHyt, B) ;
				   EnableWindow(BNFirstHyt, B) ;
				   EnableWindow(STFirstHyt, B) ;

				   ModeChanged = 1 ;   // the mode has changed

			   break ;

		   // This message can arise from -
		   //   A click in the edit box
		   //   Typing into the box
		   //   The program writing text to the box
		   case IDC_E_FIRSTHEIGHT: 
			   {
				   double temp ;
			     GetDlgItemText(hDlg, IDC_E_FIRSTHEIGHT, buff, 20) ;
			     temp = atof(buff) ;
			     if (temp != FirstFrac) // but if any change, use it.
			      {
				   FirstFrac = temp ;
			       SetUDPos(UDFirstHyt,(int)(1000.0 * FirstFrac)) ;
			       FracChanged = 1 ;	// the first fraction has changed
				   UsingDefault = 0 ;   // cancel default usage
			      }
			   }
			   break ;

		   case IDC_B_DEF_FIRSTHEIGHT:	// use default
			   {
				   char bf[20] ;
			   FirstFrac = 1.0 / (double)Levels ;
			   sprintf(bf,"%4.3f", FirstFrac) ;
			   SetDlgItemText(hDlg, IDC_E_FIRSTHEIGHT, bf) ;
			   UsingDefault = 1 ;
			   }
			   break ;

/* This causes the program to crash.  Why??? 

		   case IDC_EDIT_HEIGHTS: // edit box has changed

			   levs = GetDlgItemInt(hDlg, IDC_EDIT_HEIGHTS, &isOK, FALSE ) ;

				if (!(levs % 2)) // if levs is even
				{
					if (levs > Levels)   // we're going up.
					{
					 Levels = levs + 1 ; // so one more
					}
					else
					if (levs < Levels)   // we're going down.
					{
					 Levels = levs - 1 ; // so one less
					}
				}
				else                    // levs is already odd -- it's OK.
					Levels = levs ;

		B->NumHyts = Levels ;
		SetDlgItemInt(hDlg,IDC_EDIT_HEIGHTS,Levels,TRUE) ;
		SetUDPos(UDHyts, Levels) ;

			   break ; */

		   case IDOK:
		       if (OldLevels == Levels && !ModeChanged && !FracChanged)
			   goto skip ;
			   RestoreExclusions() ;
	    	   OldLevels = Levels ;
			   ModeChanged = 0 ;
			   EndDialog(hDlg,IDOK) ;
			   break ;

		   case IDCANCEL:
skip:
			   Levels = OldLevels ;
			   ModeChanged = 0 ;
	           SetDlgItemInt(hDlg,IDC_EDIT_HEIGHTS,Levels,TRUE) ;
			   EndDialog(hDlg,IDCANCEL) ;
			   break ;

		   default:
			   break ;
		   } // switch(LOWORD)(wParam)) 
		   break ;// WM_COMMAND

	default:
		break ;
	} // switch(msg)

	return FALSE ;
}

/******************************************************************
	                    Details Dialogue
*******************************************************************/
BOOL CALLBACK DetailDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam, 
LPARAM lParam )
{
  int n, items ;

	switch(msg)
	{

case WM_INITDIALOG:
	// Show "backdrop" bud details, or "particulars".

	if ((strlen(pBudResults->BudSpecTxt)) != 0) 
	SetDlgItemText(hDlg,IDC_ED_IDENTITY, pBudResults->BudSpecTxt) ;
	else
	SetDlgItemText(hDlg,IDC_ED_IDENTITY, Bud_ID->FriendlyID) ;

	if ((strlen(pBudResults->BudPlaceTxt)) != 0)
	SetDlgItemText(hDlg,IDC_ED_PLACE,	 pBudResults->BudPlaceTxt) ;
	else
	SetDlgItemText(hDlg,IDC_ED_PLACE,    Bud_ID->FriendlyPlace) ;

	SetDlgItemText(hDlg,IDC_ED_LATITUDE, pBudResults->BudLatitudeTxt) ;
	SetDlgItemText(hDlg,IDC_ED_LONGITUDE,pBudResults->BudLongitudeTxt) ;

	if ((strlen(pBudResults->BudDateTxt)) != 0)
	SetDlgItemText(hDlg,IDC_ED_DATE,     pBudResults->BudDateTxt) ;
	else
	SetDlgItemText(hDlg,IDC_ED_DATE,     Bud_ID->FriendlyDate) ;

	SetDlgItemText(hDlg,IDC_ED_TIME,     pBudResults->BudTimeTxt) ;
	SetDlgItemText(hDlg,IDC_IMAGE_FILE,  pBudResults->BudImageFile) ;
	SetDlgItemText(hDlg,IDC_DATA_FILE,   pBudResults->BudDataFile) ;
	SetDlgItemText(hDlg,IDC_TEXT_FILE,   pBudResults->BudTextFile) ;
	if (autotracked)
	SetDlgItemText(hDlg,IDC_TRACK_FILE,  szTrkFile) ;
	
	// Fill in the list box with the bud dimensions

	for ( n = 0, items = DimensionItems ; n < items ; n++)
	
		SendDlgItemMessage(hDlg,
			               IDC_COMBO_DIMENSIONS,
						   CB_INSERTSTRING,
						   (WPARAM)n,
						   (LPARAM)((LPCSTR) DimenCombo[n])) ;
	
	// Select the "framing" dimensions into the edit box

	    SendDlgItemMessage(hDlg,
			               IDC_COMBO_DIMENSIONS,
						   WM_SETTEXT,
						   (WPARAM)0,
						   (LPARAM)((LPCSTR) DimenCombo[0])) ;

	// Fill the list box with Lambdas and MRDs

	for ( n = 0, items = ResultItems ; n < items ; n++ )

		SendDlgItemMessage(hDlg,
			               IDC_COMBO_LAMBDAS,
						   CB_INSERTSTRING,
						   (WPARAM)n,
						   (LPARAM)((LPCSTR) ResultCombo[n])) ;

	// Select the projective whole-width Lambda and MRD
	// into the edit box.

	    SendDlgItemMessage(hDlg,
			               IDC_COMBO_LAMBDAS,
						   WM_SETTEXT,
						   (WPARAM)0,
						   (LPARAM)((LPCSTR) ResultCombo[0])) ;
		
	return (TRUE) ;
	break ;

case WM_COMMAND:
	
	switch(LOWORD(wParam))
	{
	case IDC_COMBO_DIMENSIONS:
	break ;

	case IDC_COMBO_LAMBDAS:
	break ;

	case IDOK:

	GetDlgItemText(hDlg,IDC_ED_IDENTITY, pBudResults->BudSpecTxt,255) ;
	GetDlgItemText(hDlg,IDC_ED_IDENTITY, Bud_ID->FriendlyID,255) ;
	GetDlgItemText(hDlg,IDC_ED_PLACE,    pBudResults->BudPlaceTxt,255) ;
	GetDlgItemText(hDlg,IDC_ED_PLACE,    Bud_ID->FriendlyPlace,255) ;
	GetDlgItemText(hDlg,IDC_ED_LATITUDE, pBudResults->BudLatitudeTxt,80) ;
	GetDlgItemText(hDlg,IDC_ED_LONGITUDE,pBudResults->BudLongitudeTxt,80) ;
	GetDlgItemText(hDlg,IDC_ED_DATE,     pBudResults->BudDateTxt,80) ;
	GetDlgItemText(hDlg,IDC_ED_DATE,     Bud_ID->FriendlyDate,255) ;
	GetDlgItemText(hDlg,IDC_ED_TIME,     pBudResults->BudTimeTxt,80) ;
	EndDialog(hDlg,IDOK) ;

	return (TRUE) ;
	break ;

	case IDCANCEL:
	EndDialog(hDlg,IDCANCEL) ;
	return (TRUE) ;
	break ;
	
	default:
		break ;
	}
	break ;
}
		return FALSE ;

}

/******************************************************************
	                    Calibration Dialogue
*******************************************************************/
BOOL CALLBACK CalibDlgProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam, 
LPARAM lParam )
{
	     //HWND hW ;
static   HWND hCAL ;
static double factor = 0.1 ;
       static value ;
	     char buff[128] ;

	switch(msg)
	{

     case WM_INITDIALOG:
		 
		 hCAL = GetDlgItem(hDlg, IDC_U_CAL_DISTANCE) ;

		 SetUDRng(hCAL, 10000, 0) ; 

		 sprintf(buff,"%4.3f", CalSize) ;

		 SetDlgItemText(hDlg,
			 IDC_CAL_DISTANCE,
			 buff
			 ) ;

		 SetUDPos( hCAL, (int)(CalSize / factor)) ;
		 
		 if (factor == 10.0)
		 CheckRadioButton(hDlg,
			              IDC_R_TEN,
						  IDC_R_HNDTH,
						  IDC_R_TEN
						 ) ;

		 if (factor == 1.0)
		 CheckRadioButton(hDlg,
			              IDC_R_TEN,
						  IDC_R_HNDTH,
						  IDC_R_ONE
						 ) ;

		 if (factor == 0.1)
		 CheckRadioButton(hDlg,
			              IDC_R_TEN,
						  IDC_R_HNDTH,
						  IDC_R_TENTH
						 ) ;

		 if (factor == 0.01)
		 CheckRadioButton(hDlg,
			              IDC_R_TEN,
						  IDC_R_HNDTH,
						  IDC_R_HNDTH
						 ) ;
		switch (Units)
		{
		case IMPERIAL:
		 CheckRadioButton(hDlg,
			 IDC_CAL_IMPERIAL, IDC_CAL_IU, IDC_CAL_IMPERIAL) ;
		 break ;

		case METRIC:
		 CheckRadioButton(hDlg,
			 IDC_CAL_IMPERIAL, IDC_CAL_IU, IDC_CAL_METRIC) ;
		 break ;

		case IMAGEUNITS:
		 CheckRadioButton(hDlg,
			 IDC_CAL_IMPERIAL, IDC_CAL_IU, IDC_CAL_IU) ;
		 break ;
		}
	 return (TRUE) ;
	 break ;
/**
		case WM_VSCROLL:

			hW = (HWND)lParam ;
			
			if (hW == hCAL)
			{
				 CalSize = factor * (double)GetUDPos(hCAL) ;
			     sprintf(buff,"%4.3f", CalSize) ;
				 SetDlgItemText(hDlg, IDC_CAL_DISTANCE, buff) ;
			}

			break ;
**/

		case WM_NOTIFY:
			{
				NM_UPDOWN * ud ;
				NMHDR hdr ;

				ud = (NM_UPDOWN *)lParam ;
				hdr = ud->hdr ;

				switch(hdr.code)
				{
					int newpos ;

				case UDN_DELTAPOS:
					if ((newpos = ud->iPos + ud->iDelta) < 0)
						 newpos = 0 ;
					CalSize = factor * (double)newpos ;
					sprintf(buff,"%4.3f", CalSize) ;
					SetDlgItemText(hDlg, IDC_CAL_DISTANCE, buff) ;
					break ;
				}
			}
			break ;

	 case WM_COMMAND:

		 switch(HIWORD(wParam)) // edit box has changed
		 {
		 case EN_CHANGE:

		  switch(LOWORD(wParam)) // which one? (the only one, idiot!)
		  {
		  case IDC_CAL_DISTANCE:

          GetDlgItemText(hDlg, IDC_CAL_DISTANCE, buff, 128) ;
		  CalSize = atof(buff) ;
		  //SetUDPos(hCAL,(int)(CalSize / factor)) ;

              break ;

		  default:
			  break ;
		  }
		     break ;

		 default:
			 break ;
		 }

		 switch(LOWORD(wParam))	// other commands
		 {
		 case IDC_R_TEN:
			 if (IsDlgButtonChecked(hDlg,IDC_R_TEN)) 
			 factor = 10.0 ;
			 break ;

		 case IDC_R_ONE:
			 if (IsDlgButtonChecked(hDlg,IDC_R_ONE)) 
			 factor = 1.0 ;
			 break ;

		 case IDC_R_TENTH:
			 if (IsDlgButtonChecked(hDlg,IDC_R_TENTH)) 
			 factor = 0.1 ;
			 break ;

		 case IDC_R_HNDTH:
			 if (IsDlgButtonChecked(hDlg,IDC_R_HNDTH)) 
			 factor = 0.01 ;
			 break ;

		 case IDOK:
		     if (IsDlgButtonChecked(hDlg, IDC_CAL_IMPERIAL))
			 {Units = IMPERIAL ; goto jmp ; }
		     if (IsDlgButtonChecked(hDlg, IDC_CAL_METRIC))
			 {Units = METRIC ;   goto jmp ; }
		     if (IsDlgButtonChecked(hDlg, IDC_CAL_IU))
			  Units = IMAGEUNITS ;
			 
jmp:         GetDlgItemText(hDlg, IDC_CAL_DISTANCE, buff, 128) ;
			 CalSize = atof(buff) ;

			 EndDialog(hDlg,IDOK) ;
			 break ;

		 case IDCANCEL:
			 EndDialog(hDlg,IDCANCEL) ;
			 break ;

		 default:
			 break ;
		 }
	     break ;
	}
		return (FALSE) ;
}

/*******************************
	 About
 *******************************/
BOOL CALLBACK AboutProc(
  HWND hDlg,
  UINT msg, 
WPARAM wParam, 
LPARAM lParam )
{
	switch (msg)
	{
      case WM_INITDIALOG:
		  return (TRUE) ;
		  break ;

	  case WM_COMMAND:
		 switch(LOWORD(wParam))
		 {
		 case IDOK:
	     EndDialog(hDlg,IDOK) ;
		 break ;
		 }

		 default: break ;
	}
	return FALSE ;
}

//******************************************************************
//  Put up the splash screen
//******************************************************************

long CALLBACK  BannerWndProc(hWnd, msg, wParam, lParam)
HWND hWnd;                      // window handle                 
UINT msg;                       // type of message               
WPARAM wParam;                  // additional information        
LPARAM lParam;                  // additional information        
{
  PAINTSTRUCT ps ;
  HDC hdc, hmemDC ;
  HBITMAP oBm ;
					   
       
    switch (msg)
    {
		double aspect ;
		int cx, w, h ;

        case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps) ;      // get updated DC
        hmemDC = CreateCompatibleDC(hdc) ; // make mem DC
        oBm = SelectObject(hmemDC,hFlag) ; // select in the splash bitmap

		aspect = 250.0 / 320.0 ;
		    cx = GetSystemMetrics(SM_CXSCREEN) ;
		     w = cx / 3 ;
			 h = (int)((double)w * aspect) ;

		SetStretchBltMode(hdc, COLORONCOLOR) ;

        StretchBlt(hdc,						   // show it
			       0, 0,
			       w, h,
			       hmemDC,
			       0, 0,
				   320, 250,
			       SRCCOPY) ;

        SelectObject(hmemDC,oBm) ;         // select out bitmap
        DeleteDC(hmemDC) ;                 // mem DC away
        EndPaint(hWnd, &ps ) ;             // DC away
        return 0 ;
        break ; 

        default:                  //Passes it on if unprocessed 
            return (DefWindowProc(hWnd, msg, wParam, lParam));
    }
    return ((long)NULL);

}

// **********************************************
// Return image co-ordinates in image units
// from client co-ordinates.
// **********************************************
void CliToImg( LPDPOINT ip, LPPOINT cp )
{
	double wid, xoffset, yoffset ;

	          wid = (double)Inset[MeasureWindow].w ;	       // in screen pixels.
	      xoffset = (double)Inset[MeasureWindow].xo ;
	      yoffset = (double)Inset[MeasureWindow].yo ;

	ip->x = ((double)cp->x - xoffset) ;        // in screen pixels

	ip->y = (double)((rcb.bottom -
					 (int)((double)cp->y +
					  yoffset))) ;		       // in screen pixels

	ip->x /= wid ;							   // in IMAGEUNITS
	ip->y /= wid ;
}

// ***************************************************
// Return client co-ordinates from image co-ordinates.
// ***************************************************
void ImgToCli(LPPOINT cp, LPDPOINT ip)
{
	double wid, xoffset, yoffset ;

	    wid = (double)Inset[MeasureWindow].w ;	  // all in screen pixels
	xoffset = (double)Inset[MeasureWindow].xo ;
	yoffset = (double)Inset[MeasureWindow].yo ;

	// ip->x and ip->y are in IMAGEUNITS

	cp->x = (int)(ip->x * wid + xoffset) ;
	cp->y = rcb.bottom - (int)( ip->y * wid + yoffset ) ;
}

/**********************************************
    What sort of file have we?
 **********************************************/
int CheckFileType( void )
/*
 Returns: 0 => "BM", Bitmap
          1 => "BG", Bud file in   Graham format
          2 => "BL", Bud file in Lawrence format
		  3 => "JPEG"  Bud file in JPEG's JFIF or FujiFilm's Exif format.
          4 => "xx", where xx is none of the above, a non-standard format
 
 These values are #defined as constants, to allow
 use in switch(){} statements.
*/
{
 HFILE hbud ;
 OFSTRUCT of ;
 int i, j, cbread ;
 static char *ftyp[] = { "BM", "BG", "BL", "JFIF", "Exif" } ;
 static char buff[sizeof(BITMAPFILEHEADER)] ;
 DWORD errorcode ;
 char error[128], str[20] ;

 if ((hbud = OpenFile(szFile, &of, OF_READ)) == HFILE_ERROR)
 {
	 errorcode = GetLastError() ;
	 sprintf(error,"Error code: %ld",errorcode) ;
	 MessageBox(
		 NULL,
		 error,
		 "OpenFile error",
		 MB_ICONHAND|MB_OK
		       ) ;
 }
 cbread = _hread(hbud, buff, sizeof(BITMAPFILEHEADER)) ;
 _lclose( hbud ) ;		 // close the file

 buff[cbread+1] = '\0' ; // make ASCIIZ string
 
 // Check for a .JPG file: the four bytes beginning at index 6 read "JFIF"
 for (i = 6, j = 0 ; i < 10 ; str[j++] = buff[i++]) ;
 str[4] = '\0' ;

 if (!strcmp(str,"JFIF")) return JPtyp ;

 // Fujifilm style jpegs have "Exif". Let's see if this works..

 if (!strcmp(str,"Exif")) return JPtyp ;

 // .. it did!
 
 // Check for other types of file
 for (i = 0 ; i < 3 ; i++)
  { 
  if ( _strnicmp( buff, ftyp[i], 2) == 0 ) // not case sensitive
   {
    if ( i == 0) return BMtyp ;
    if ( i == 1) return BGtyp ;
    if ( i == 2) return BLtyp ;
   }
  }
  return OTtyp ;
  
}

void GetLineStorage( void )
{
			   // scans are RGB buffer based.

	if (GlobalSize( lum )) GlobalFree( lum ) ;
	lum = (int *)GlobalAlloc(GPTR, (ws + 16) * sizeof(int)) ;

	if (GlobalSize( dlum )) GlobalFree( dlum ) ;
	dlum = (int *)GlobalAlloc(GPTR, (ws + 16) * sizeof(int)) ;

	if (GlobalSize( hue )) GlobalFree( hue ) ;
	hue = (double *)GlobalAlloc(GPTR, (ws + 16) * sizeof(double)) ;

	if (GlobalSize( dhue )) GlobalFree( dhue ) ;
	dhue = (double *)GlobalAlloc(GPTR, (ws + 16) * sizeof(double)) ;

	if (GlobalSize( sat )) GlobalFree( sat ) ;
	sat = (double *)GlobalAlloc(GPTR, (ws + 16) * sizeof(double)) ;

               stored = set ;
}

/**********************************************************************
  Load, decompress, and prepare a full-colour JPEG file for work
  using ISource21.dll from Chris Losinger, of "Smaller Animals" Software.
 **********************************************************************/
int LoadJPformat( void )
{
	HISSRC hSrc ;
	   int ntxt ; // number of text strings found

	// Free any memory already in use.
	// Final use freed on quitting app.
	
	if (GlobalSize(hTempo)) GlobalFree(hTempo) ;
	if (GlobalSize(hTemp))  GlobalFree(hTemp) ;

	if (GlobalSize(hRGB)) 
		  GlobalFree( hRGB ) ;

	if (GlobalSize(hGRY)) ;
		  GlobalFree( hGRY ) ;

	if (GlobalSize(hSTA))
		  GlobalFree( hSTA ) ;

			hSrc = _ISOpenFileSource( szFile) ;
			_ISClearJPGInputText() ;
			_ISSeek(hSrc, 0, 0) ;

			hRGB = _ISReadJPG
				(
				  hSrc,
				  &dibwid,
				  &dibhyt,
				  24
				) ;

			pRGB = (BYTE *)hRGB ;

			// October 2013
			//
			// We make JPEG our standard and only image format, and
			// make use of the JPEG COM facility to embed all the
			// bud instance's data as text in the JPEG. So here we
			// not only load the image for display and processing,
			// we bring in the data as well.

			ntxt = _ISGetJPGInputTextCount() ; // get embedded string count

//12345
			if (ntxt)	// get embedded strings
			{
				char *txt ;
				 int i ;

				for (i = 0 ; i < ntxt ; i++)
				{
					txt = _ISGetJPGInputText(i) ;
					budData[i] = (char *)GlobalAlloc(GPTR, (strlen(txt) + 2) * sizeof(char)) ;
					strcpy(budData[i], txt) ;  // need CRLF? Maybe, if (re)building an INI
				}
				// free the memory
				for (i = 0 ; i < ntxt; i++) GlobalFree(budData[i]);
			}
			_ISClearJPGInputText();
			_ISCloseSource(hSrc) ;

			hSrc = _ISOpenFileSource( szFile) ;
			_ISSeek(hSrc, 0, 0) ; 

			hGRY = _ISReadJPG
				(
				  hSrc,
				  &dibwid,
				  &dibhyt,
				  24
				) ;
			pGRY = (BYTE *)hGRY ;

			_ISRGBToGrayScale24
				(
				 pGRY,
				 dibwid,
				 dibhyt
				) ;

			_ISCloseSource(hSrc) ;

			hSrc = _ISOpenFileSource( szFile) ;
			_ISSeek(hSrc, 0, 0) ; 

			hSTA = _ISReadJPG
				(
				  hSrc,
				  &dibwid,
				  &dibhyt,
				  24
				) ;
			pSTA = (BYTE *)hSTA ;

			_ISCloseSource(hSrc) ;

   showTrack = ImgSig = 0 ;
       which = COLOUR ;

	// No error handler in this function. Protection in place elsewhere,
	// but may need some here too. We'll see!
	return 1 ;
}

/*********************************************************************

  Convert a BMP to JPG, save the JPG and Delete the BMP

 *********************************************************************/
void BMPtoJPG(char * infile, char * ofile) // infile the fully qualified path of a BMP
{
	HISSRC   hSrc ;
	HISDEST  hDest ;
	OFSTRUCT of ;
	HFILE    hF ;
	UINT32   sw, sh ;
	DWORD    clen = MAX_COMPUTERNAME_LENGTH + 1 ;
	char     cname[MAX_COMPUTERNAME_LENGTH + 1] ;

	if (GlobalSize(hRGB)) 
		  GlobalFree( hRGB ) ;

			hSrc = _ISOpenFileSource( infile ) ;

		  hRGB = _ISReadBMP
				(
				  hSrc,
				  &sw,
				  &sh,
				  24,
				  NULL
				) ;

			pRGB = (BYTE *)hRGB ;

			_ISCloseSource(hSrc) ;

			hDest = _ISOpenFileDest( ofile ) ;			// ofile is the fully qualified path of a JPG

			_ISAddJPGOutputText(  DropPath( ofile ) ) ;	// write the file-name     to the image file as embedded text
			_ISAddJPGOutputText( GetMyPath( ofile ) ) ;	// write the original path to the image file as embedded text
			    GetComputerName( cname, &clen ) ;		// get the originating computer name
			_ISAddJPGOutputText( cname ) ;				//           embed the computer name

						_ISWriteJPG
						(
							hDest,
							pRGB,
							sw,
							sh,
							JPGQuality,
							0,
							24,
							NULL
						) ;

						_ISCloseDest(hDest) ;

			_ISClearJPGOutputText() ;					// clear output texts


				GlobalFree(hRGB) ;

				if ((hF = OpenFile(infile, &of, OF_EXIST)) != HFILE_ERROR)
				{
					 hF = OpenFile(infile, &of, OF_DELETE) ;
				}
}

int LoadBMformat( void )
{
	HISSRC hSrc ;

	if (GlobalSize(hTempo)) GlobalFree(hTempo) ;
	if (GlobalSize(hTemp )) GlobalFree(hTemp) ;

	if (GlobalSize(hRGB)) 
		  GlobalFree( hRGB ) ;

	if (GlobalSize(hGRY)) ;
		  GlobalFree( hGRY ) ;

	if (GlobalSize(hSTA))
		  GlobalFree( hSTA ) ;

   // Create and fill RGB buffers

			hSrc = _ISOpenFileSource( szFile) ;

			//_ISSeek(hSrc, 0, 0) ;

			hRGB = _ISReadBMP
				(
				  hSrc,
				  &dibwid,
				  &dibhyt,
				  24,
				  NULL
				) ;

			pRGB = (BYTE *)hRGB ;

			_ISCloseSource(hSrc) ;


			hSrc = _ISOpenFileSource( szFile) ;

			hGRY = _ISReadBMP
				(
				  hSrc,
				  &dibwid,
				  &dibhyt,
				  24,
				  NULL
				) ;
			pGRY = (BYTE *)hGRY ;

			_ISCloseSource(hSrc) ;

			_ISRGBToGrayScale24
				(
				 pGRY,
				 dibwid,
				 dibhyt
				) ;

			hSrc = _ISOpenFileSource( szFile) ;

			hSTA = _ISReadBMP
				(
				  hSrc,
				  &dibwid,
				  &dibhyt,
				  24,
				  NULL
				) ;
			pSTA = (BYTE *)hSTA ;

			_ISCloseSource(hSrc) ;

	showTrack = ImgSig = 0 ;
		which = COLOUR ;

    return(1) ;
}

void ImageSig( UINT32 xpch, UINT32 ypch )
/*
    A swept "patch" of pixels from the image is scanned for the number
	of occurrences in the patch of pixels with the RGB value of the
	pixel at the centre of the patch.
	
	The ratio of this number to the total number of pixels
	in the patch is the statistical probability (here taken as the
	true Probability, pr) of occurrence of that value in the patch.

    Putting this another way, pr is the probability that another pixel
	randomly chosen from the patch will have the central pixel's value.
	
	The Significance of the central pixel's value is here defined as its
	improbability, 1 - pr: that is, if it is improbable, it is one of
	few, such as occur at a boundary, and thus is likely actually to be
	a boundary pixel.  It is intended that boundary-detection gain some
	independence from the actual values at boundaries. 

    A false-colour image of the bud in terms of its significances is
	prepared. It provides some statistical corroboration of tracking and
	measurement.
*/
{
static UINT32 w, h, x, y, xs, ys ;
static UINT32 xstart, ystart, xstop, ystop ;
static UINT32 xhalf ;
static UINT32 yhalf;
static        i ;
static    int bin ;
static   BYTE * p ;
static   BYTE v, vs ;
static double pr, Npch ;

    StartWait() ;

	    w = dibwid ;
		h = dibhyt ;
	xhalf = (xpch - 1) / 2 ;
	yhalf = (ypch - 1) / 2 ;
	 Npch = (double)(xpch * ypch) ;

	 // try all pixels in image as patch-centres.
	 //
	 //   This way is wasteful: there is a lot of
	 //   repetition. Only need to get new right
	 //   column, and lose the leftmost, per
	 //   horizontal move after the	first, and
	 //   a new bottom row per vertical move 
	 //   after the first, losing the topmost. Ummmm....

	 for (ys = 0 ; ys < h ; ys++)
	 {
	  for (xs = 0 ; xs < w ; xs++)
	  {		
		// central pixel's RGB buffer location
		    p = pGRY + 3 * (w * ys + xs) ;
		  
		// gray value of pixel at centre of patch
		   vs = *p ;
	    // clear the patch bin 
		  bin = 0 ;
		  
		// first assume scanned patch
		// is in bounds

			   xstart = xs - xhalf ;
			    xstop = xs + xhalf ;
			   ystart = ys - yhalf ;
			    ystop = ys + yhalf ;

	    // but adjust patch location
		// if patch put out of bounds
		   if ( xs < xhalf )
		    { 
			   xstart = 0 ;
			    xstop = xpch ;
		    }

		   if ( xs > w - xhalf )
		    {
			   xstart = w - xpch ;
			    xstop = w ;
		    }

		   if ( ys < yhalf )
		    {
			   ystart = 0 ;
			    ystop = ypch ;
		    }

		   if ( ys > h - yhalf )
		   {
			   ystart = h - ypch ;
			    ystop = h ;
		   }

		// scan the patch for number of pixels 
		// with value vs.

		for (y = ystart ; y < ystop ; y++)
		{
		 for (x = xstart ; x < xstop ; x++)
		 {
		   p = pGRY + 3 * (w * y + x) ;
		   if ( *p == vs )
		   {
			   bin++ ;
		   }
		 } // for x
	    } // for y

	   // statistical probability of vs
		 pr = (double)bin / Npch ;
		 
	  // corresponding location in
	  // statistical-image buffer
		    p = pSTA + 3 * (w * ys + xs) ;

	  // value by "significance" (improbability)
		    v = (BYTE)ceil(255.0 * (1.0 - pr)) ;

	  // false colour
		if ( v >=   0 && v <  253 )
			{ *p = *(p+1) = *(p+2) = 255 ;	goto skip ; }	// white

		if ( v >= 253 && v <= 254 )
			{ *p = *(p+1) = *(p+2) = 192 ;	goto skip ; }	// gray

		if ( v > 254 )
			  *p = *(p+1) = *(p+2) = 0 ;					// black

/****
		if ( v >=    0 && v <  180 )
			{ *p = *(p+1) = *(p+2) = 0 ;	   goto skip : } // black
		if ( v >=  180 && v <  190 )
			{ *p = *(p+1) = 0 ; *(p+2) = 64  ; goto skip ; } // darkest blue
			
		if ( v >=  190 && v < 200 )
			{ *p = *(p+1) = 0 ; *(p+2) = 128 ; goto skip ; } // darker blue

		if ( v >= 200 && v < 210 )
			{ *p = *(p+1) = 0 ; *(p+2) = 192 ; goto skip ; } // dark blue
			
		if ( v >= 210 && v < 220 )
			{ *p = *(p+1) = 0 ; *(p+2) = 255 ; goto skip ; } // blue

		if ( v >= 220 && v < 230 )
			{ *p = 128 ; *(p+1) = 64 ; *(p+2) = 32 ; goto skip ; } // darker orange

		if ( v >= 230 && v < 240 )
			{ *p = 192 ; *(p+1) = 96 ; *(p+2) = 48 ; goto skip ; } // dark orange

		if ( v >= 240 && v < 253 )
			{ *p = 255 ; *(p+1) = 128 ; *(p+2) = 64 ; goto skip ; } // orange
//			{ *p = *(p+1) = 255 ; *(p+2) = 0 ; goto skip ; } // yellow

//			{ *p = *(p+1) = 0 ; *(p+2) = 255 ;   goto skip ; } // blue
//			{ *p = *(p+1) = *(p+2) = 0 ;         goto skip ; } // black
//			  *p = *(p+1) = *(p+2) = 255 ;                     // white
****/

skip:;
	  } // for xs
	 } // for ys

	 EndWait() ;
}

BOOL CALLBACK SigPatch(
  HWND hDlg,
  UINT msg, 
WPARAM wParam,
LPARAM lParam )
{
	//BOOL snafu ;
	static HWND hW ;
	static HWND U_Wid,    E_Wid ;
	static HWND U_Hyt,    E_Hyt ;
	static HWND B_Apply,  B_Undo ;
	static HWND B_Square, B_Match ;
	static xpchdflt = 31 ;
	static ypchdflt = 31 ;
	static  OnePass = 0 ;
	static UINT32 oldxpch, oldypch ;
	UINT32 pixels ;
	double area ;
	       char buff[50] ;

	switch (msg)
	{
       case WM_INITDIALOG:

		   U_Wid = GetDlgItem(hDlg,IDC_U_XPATCH) ;
		   E_Wid = GetDlgItem(hDlg,IDC_E_XPATCH) ;
		   U_Hyt = GetDlgItem(hDlg,IDC_U_YPATCH) ;
		   E_Hyt = GetDlgItem(hDlg,IDC_E_YPATCH) ;

		   B_Apply  = GetDlgItem(hDlg,IDC_B_SIG_APPLY) ;
		   B_Undo   = GetDlgItem(hDlg,IDC_B_SIG_UNDO ) ;
		   B_Square = GetDlgItem(hDlg,IDC_B_MAKESQUARE ) ;
		   B_Match  = GetDlgItem(hDlg,IDC_B_SIG_MATCH_IMG ) ;

		  if (gotimage)
		  {
	       SetUDRng(U_Wid, dibwid, 5) ;
	       SetUDRng(U_Hyt, dibhyt, 5) ;
		  }
		  else
		  {
	       SetUDRng(U_Wid, 5001, 5) ;
	       SetUDRng(U_Hyt, 5001, 5) ;
		  }

	       SetUDPos(U_Wid, xpch) ;
	       SetUDPos(U_Hyt, ypch) ;

		   oldxpch = xpch ;
		   oldypch = ypch ;

			   if ( xpch != ypch)
				   EnableWindow(B_Square, TRUE) ;
			      else
				   EnableWindow(B_Square, FALSE) ;

		   return TRUE ;
		   break ;

	   case WM_VSCROLL:

	    hW = (HWND)lParam ;

			if (hW == U_Hyt)
			{
				SendMessage
				   (
					E_Hyt,
					WM_GETTEXT,
					50,
				   (LPARAM)buff
				   ) ;

				pixels = atoi(buff) ;

				if (!(pixels % 2)) // if pixels is even
				{
					if (pixels > ypch)   // we're going up.
					{
					 ypch = pixels + 1 ; // so one more
					}
					else
					if (pixels < ypch)   // we're going down.
					{
					 ypch = pixels - 1 ; // so one fewer
					}
				}
				else                    // pixels is already odd -- it's OK.
					ypch = pixels ;

		SetDlgItemInt(hDlg,IDC_E_YPATCH,ypch,TRUE) ;

			   if ( xpch != ypch)
				   EnableWindow(B_Square, TRUE) ;
			      else
				   EnableWindow(B_Square, FALSE) ;

		EnableWindow(B_Undo,  TRUE) ;
		EnableWindow(B_Apply, TRUE) ;
			}

			if (hW == U_Wid)
			{
				SendMessage
				   (
					E_Wid,
					WM_GETTEXT,
					50,
				   (LPARAM)buff
				   ) ;

				pixels = atoi(buff) ;

				if (!(pixels % 2)) // if pixels is even
				{
					if (pixels > xpch)   // we're going up.
					{
					 xpch = pixels + 1 ; // so one more
					}
					else
					if (pixels < xpch)   // we're going down.
					{
					 xpch = pixels - 1 ; // so one less
					}
				}
				else                    // pixels is already odd -- it's OK.
					xpch = pixels ;

		SetDlgItemInt(hDlg,IDC_E_XPATCH,xpch,TRUE) ;

			   if ( xpch != ypch)
				   EnableWindow(B_Square, TRUE) ;
			      else
				   EnableWindow(B_Square, FALSE) ;

		EnableWindow(B_Undo,  TRUE) ;
		EnableWindow(B_Apply, TRUE) ;

			}

		   break ; // WM_VSCROLL

	   case WM_COMMAND:
		   switch(LOWORD(wParam))
		   {

		   case IDC_X_DFLT:
		oldxpch = xpch ;
		SetDlgItemInt(hDlg,IDC_E_XPATCH,xpchdflt,TRUE) ;
		xpch = xpchdflt ;
			   if ( xpch != ypch)
				   EnableWindow(B_Square, TRUE) ;
			      else
				   EnableWindow(B_Square, FALSE) ;
		EnableWindow(B_Undo,  TRUE) ;
		EnableWindow(B_Apply, TRUE) ;

			   break ;

		   case IDC_Y_DFLT:
		oldypch = ypch ;
		SetDlgItemInt(hDlg,IDC_E_YPATCH,ypchdflt,TRUE) ;
		ypch = ypchdflt ;
			   if ( xpch != ypch)
				   EnableWindow(B_Square, TRUE) ;
			      else
				   EnableWindow(B_Square, FALSE) ;
		EnableWindow(B_Undo,  TRUE) ;
		EnableWindow(B_Apply, TRUE) ;

			   break ;

		   case IDC_B_SIG_APPLY:
			   oldxpch = xpch ;
			   oldypch = ypch ;
			   OnePass = ((xpch == (UINT32)dibwid
				           ||
						   xpch == (UINT32)dibwid - 1)
				           &&
						  (ypch == (UINT32)dibhyt
						   ||
						   ypch == (UINT32)dibhyt - 1))
						  ? 1 : 0 ;
			   ImageSig( xpch, ypch ) ;
			    ImgSig = 1 ;
			   ivrc(hWndBud,&rctl[Gry],FALSE) ;
			   ivrc(hWndBud,&rcimg,    FALSE) ; 
			   ivrc(hWndRslt, NULL,    FALSE) ;
		       EnableWindow(B_Undo,  TRUE ) ;
		       EnableWindow(B_Apply, FALSE) ;
			   break ;

		   case IDC_B_MAKESQUARE:
			   oldxpch = xpch ;
			   oldypch = ypch ;
			   // preserve patch area, if possible
			   area = (double)(xpch * ypch) ;
			   // find side size
			   xpch = ypch = (UINT32)ceil(sqrt(area)) ;
			   // check for side too big
			   if (xpch > (UINT32)dibwid || ypch > (UINT32)dibhyt)
			   {
				// if so, take the shorter dimension
				// of the RGB buffer as the patch side.
				   if ( dibwid < dibhyt)
					   xpch = ypch = (UINT32)dibwid ;
				   else
					   xpch = ypch = (UINT32)dibhyt ;
			   }
			   // be sure of odd numbers
			   if (!(xpch % 2)) {--xpch ; --ypch ;}
			   // show dimensions
		       SetDlgItemInt(hDlg,IDC_E_XPATCH,xpch,TRUE) ;
		       SetDlgItemInt(hDlg,IDC_E_YPATCH,ypch,TRUE) ;
			   EnableWindow(B_Square, FALSE) ;
			   // allow undo
		       EnableWindow(B_Undo,  TRUE) ;
			   // allow apply
		       EnableWindow(B_Apply, TRUE) ;
			   break ;

		   case IDC_B_SIG_MATCH_IMG:
			   oldxpch = xpch ;
			   oldypch = ypch ;
			   // equate patch sides to image sides,
			   // but make sure the numbers are odd
			      xpch = dibwid ;
				  if (!(xpch % 2)) --xpch ;
			      ypch = dibhyt ;
				  if (!(ypch % 2)) --ypch ;
			   // show dimensions
		       SetDlgItemInt(hDlg,IDC_E_XPATCH,xpch,TRUE) ;
		       SetDlgItemInt(hDlg,IDC_E_YPATCH,ypch,TRUE) ;
			   if ( xpch != ypch)
				   EnableWindow(B_Square, TRUE) ;
			      else
				   EnableWindow(B_Square, FALSE) ;
		       EnableWindow(B_Undo,  TRUE) ;
		       EnableWindow(B_Apply, TRUE) ;
			   break ;

		   case IDC_B_SIG_UNDO:
			   if (xpch != oldxpch || ypch != oldypch)
			   {
			   xpch = oldxpch ;
			   ypch = oldypch ;
			   SetDlgItemInt(hDlg,IDC_E_XPATCH,xpch,TRUE) ;
			   SetDlgItemInt(hDlg,IDC_E_YPATCH,ypch,TRUE) ;
			   EnableWindow(B_Apply, TRUE) ;
			   }
			   EnableWindow(B_Undo, FALSE) ;
			   break ;
/*
		   case IDC_E_XPATCH:
			   xpch = GetDlgItemInt(hDlg, IDC_E_XPATCH, &snafu, FALSE) ;
			   EnableWindow(B_Apply, TRUE) ;
			   break ;

		   case IDC_E_YPATCH:
			   ypch = GetDlgItemInt(hDlg, IDC_E_YPATCH, &snafu, FALSE) ;
			   EnableWindow(B_Apply, TRUE) ;
			   break ;
*/
		   default:
			   break ;
		   } // switch(LOWORD)(wParam)) 
		   break ;// WM_COMMAND

	default:
		break ;
	} // switch(msg)
	return FALSE ;
}

// **********************************************************
//  Files in the format from an earlier bud prog. of Graham's..
// **********************************************************
void LoadBGformat( void )  // One fine day I'll come to you, tra la la...
{
 ;
}

// **********************************************************
//  Files in Lawrence's original "Digithurst" format.
// **********************************************************
void LoadBLformat( void ) // Somewhere, over the Rainbow...
{
 ;
}

int CheckLumPeakLimit( int count )
{
	 char msg[255] ;

	if (count > MAXPEAKS - 50)
	{
	 sprintf(msg,
"WARNING: The Number of Luminance Peaks\n" \
"is dangerously close to the Limit.\n\n" \
"\n\nWe recommend raising either the threshold" \
"\nor the smoothing-level, or both." \
"\n\nIf these measures fail," \
"\ntry reducing the image resolution."
     ) ;

	MessageBox(NULL, msg, "Imminent Scan Failure", MB_ICONEXCLAMATION|MB_OK) ;

	//if (scanning)
	//SendMessage(hWndBud, WM_COMMAND, TOGGLE_SCAN, 0L) ;

		return 1 ;
	}
	else
	if ( count > MAXPEAKS - 10)
	{
sprintf(
msg,
"The Luminance Peak storage-limit has been exceeded.\n" \
"Line-Scanning has been turned off to avoid\n" \
"crashing the computer.\n\n" \
"You may wish to -\n" \
"(1) Reduce the image resolution, and/or\n" \
"(2) Its pixel dimensions, and/or\n" \
"(3) Raise the smoothing level, and/or\n" \
"(4) Raise the threshold value,\n\n" \
"then try again.\n\n" \
"Click on the 'Camera' button for options (1) and (2).\n" \
"Click on the 'Params' button for options (3) and (4)."
) ;

	MessageBox(NULL, msg, "Array Bounds Error.", MB_ICONEXCLAMATION|MB_OK) ;

	if (scanning)
	SendMessage(hWndBud, WM_COMMAND, TOGGLE_SCAN, 0L) ;

	return 0 ;
	}
	else
		return 1 ; // no problem
}

/***********************************************

 Do a line scan entirely in RGB buffer.

 23rd October 2002:

 Allow selection of a single colour component
 into the grayscaled line - that is, the value
 of gray equal to the value of a single colour
 component.

 For most buds, the dominant colour appears to be
 red, so that a gray scale image consisting only
 of the	red component will be brightest where the
 original is reddest, and other, less red regions
 will be darker, so contrast, and hence edge-
 detection, ought to be improved

 Some buds _may_ be dominantly green, and others
 dominantly blue, so the options to choose these
 colour components are there, too.

 ***********************************************/
void ScanRGBLine(
				 BYTE * ptr,
			     UINT32 w,
			     UINT32 y,
				    int col
				)
{
	BYTE * pt, r, g, b ;
	 int *temp ;
	 int c1, c2, c3 ;
     int i, j, span ;
  static sector = 0 ;
	UINT s, sl ;
  UINT32 x ;
  double ar, ag, ab, uc, hr, hg, u, v, xx ;
  double slope, intercept ;

  span = w ;

	for ( i = 0 ; i < span ; i++ )
	{
		   x = (UINT32)(xsa + i) ;
	      pt = ptr + 3 * (y * w + x) ;
		   r = pt[0] ;
		   g = pt[1] ;
		   b = pt[2] ;

		   s = r + g + b ;
		   if (col == 0)    // All
		   sl = s ;
		   if (col == 1)	// just red
		   sl = 3 * r ;
		   if (col == 2)	// just green
		   sl = 3 * g ;
		   if (col == 3)	// just blue
		   sl = 3 * b ;

	  lum[i] = sl / 3 ;
	

if (huesat)
   {

   // chromaticities of C			  // if sum is zero or all colours same value
	if (s == 0 || (r == g && g == b)) // is monochrome, i.e. black <= gray <= white
		ar = ag = ab = onethird ;	  
	else							  // otherwise
	{								  // is polychrome i.e. coloured!
       ar = (double)r/(double)s ;	  //   red fraction of sum
       ag = (double)g/(double)s ;	  // green fraction
	   ab = (double)b/(double)s ;	  //  blue fraction
	}
	  // The chromatic interval is the distance from the "white point (1/3,1/3)",W.

	    u = ar - onethird ;	            //   red chromatic interval of C
	    v = ag - onethird ;	            // green chromatic interval	of C

 if (u == 0.0)
	slope = v * 1.0e10 ;
	else
    slope = v / u ;					    //     slope of C's "colour line"
intercept = onethird * (1.0 - slope) ;	// intercept of C's "colour line"
	   hr = - intercept / slope ;		// cut of red axis by "colour line
	   uc = itan(v, u) ;				// colour angle of C
       tc = adiff2(uc,t0) ;             // adjusted colour angle of C

								// colour     // saturated colour 
	                            // sector     //   (hue) range
								// ~~~~~~     // ~~~~~~~~~~~~~~~~
	   if (0.0 < tc && tc < tg) sector = 1 ; // red->yellow->green
	   else									  //
	   if ( tg < tc && tc < tb) sector = 2 ; // green->cyan->blue
	   else									  //
    if ( tb < tc && tc < twopi) sector = 3 ; // blue->magenta->red
	   
	// find hue and saturation

	/* 
	  
	   Hues lie in the ranges --
	   -1.0 to 0.0  bluepurple->purple->redpurple on sector 3
	    0.0 to 1.0  red->orange->yellow->lemon->green on sector 1
		1.0 to 2.0  green->greenblue->cyan->bluegreen->blue on sector 2
	*/ 

	   switch(sector)
	   {
	   case 1: hue[i] = 1.0 - (xx = (1.0 - intercept)/(1.0 + slope)) ;	// sector 1 on green to red side
			   sat[i] = (ar - onethird) / (xx - onethird) ;
		                            break ;
	   case 2: hue[i] = 2.0 - intercept ;						// sector 2 on green axis
			   sat[i] = (onethird - ar) / onethird ;
		                            break ;
	   case 3: hue[i] = hr - 1.0 ;								// sector 3 on red axis
		       sat[i] = (ar - onethird) / (hr - onethird) ;
		                            break ;
	   default:                     break ;
	   }

	   /* Saturation (by simple proportion) */
	   /*
	   if ((uc = hr - onethird) == 0.0) // colour line is vertical, use green.
	   {
	     if ( hg != onethird ) // C does not lie in W 
	       sat[i] = fabs((ag - onethird) / (hg - onethird)) ;
		 else                 // C must lie in W
		   sat[i] = 0 ;
	   }
	   else	// use red
	   sat[i] = fabs((ar - onethird)/uc) ;
	   */
     } // end of (huesat)

    }  // end of for (i...

 if (!huesat) /* we are working with a monochrome version of the image.*/
 {

         int count ;
 /*******************************
 
  9/10/2002: BugFix.

    The peak-filter arrays were too small with 100 elements, and resulted in 
    GPFs when large, richly-textured images were scanned.  Appears to be OK 
	now, but is a thing to keep an eye on!

 ********************************/
	     int pktype[MAXPEAKS] ;	// current peak type
		 int  pkpos[MAXPEAKS] ;	// peak position
	
  /* running mean of 3 smoothing,
     done scansmooth times over. */
  for ( j = 0 ; j < scansmooth ; j++ )
  {
    temp = dlum ; // borrow the differential's array for a while
   { 
    temp[0] = (2*lum[0] + lum[1]) / 3 ;				          // first
    temp[span - 1] = (lum[span - 2] + 2*lum[span - 1]) / 3 ;  // final

	// the others
    for ( i = 1 ; i < span - 1 ; i++ )
    temp[i] = (lum[i-1] + lum[i] + lum[i+1]) / 3 ;
   }
    for ( i = 0 ; i < span ; lum[i] = temp[i++] ) ;
  } 
  
  /* work the differential on the smoothed version */

  dlum[0] = c1 = c2 = c3 = nPeaks = ISONPEAK = 0 ;
    count = 1 ;
  pktype[0] = 2 ; pkpos[0] = 0 ;  // fudge

  for (i = 1 ; i < span ; i++ )
  {
     dlum[i] = abs(lum[i] - lum[i-1]) ;

	 /* Find maxima and their positions in the differential train */

	 c1 = c2 ;        // Left-shift old values
	 c2 = c3 ;
	 c3 = dlum[i] ;	  // Assign new value to rightmost

	 
	 if (c1 < c2 && c2 == c3)                    // rising to plateau
	 {
	 if (!CheckLumPeakLimit(count)) return ;     // array bounds exceeded
	  pktype[count]   = 1 ;
	   pkpos[count++] = i - 1 ;
	 }
	 else
	 if (c1 == c2 && c2 > c3)                    // falling from plateau
	 {
	 if (!CheckLumPeakLimit(count)) return ;
	  pktype[count]   = 2 ;
	   pkpos[count++] = i - 1 ;
	 }
	 else
	 if (c1 < c2 && c2 > c3)                     // peaking
	 {
	 if (!CheckLumPeakLimit(count)) return ;
	  pktype[count]   = 3 ;
	   pkpos[count++] = i - 1 ;
	 }
  }

  // Sort out the detected peaks

   for ( i = 1 ; i < count ; i++ )
   {
    if (pktype[i] == 2)
    {
     if (
	     (pktype[i - 1] == 1 ) &&
		 (pkpos[i] - pkpos[i-1] == 1)
		)
		{
		  int val, pos ;
	/* Is a pair of adjacent "high corners".
	   If above threshold, accept them both as peaks ; */

		pos = pkpos[i-1] ;
		if ((val = dlum[pos]) >= (double)threshold)
		{
	      PeakAt[nPeaks] = pos ;
	     PeakVal[nPeaks] = val ;
      /* if the cursor is on this peak, say so. */
	     if (xINS == pos ) { ISONPEAK = 1 ; onPeak = nPeaks ; }
          nPeaks++ ;
	    }

		pos = pkpos[i] ;
		if ((val = dlum[pos]) >= (double)threshold)
		{
	      PeakAt[nPeaks] = pos ;
	     PeakVal[nPeaks] = val ;
      /* if the cursor is on this peak, say so.	*/
		 if (xINS == pos) { ISONPEAK = 1 ; onPeak = nPeaks ; }
	      nPeaks++ ;
	    }
      }

        if (
	     (pktype[i - 1] == 1 ) &&
		 (pkpos[i] - pkpos[i-1] == 2)
		   )
		 {
		  int val, pos ;
	/* Is a pair of near-adjacent "high corners".
	   If above threshold, take the mid-point as a peak	*/

		 pos = (pkpos[i-1] + pkpos[i]) / 2 ;
		 if ((val = dlum[pos]) >= (double)threshold)
		 {
	       PeakAt[nPeaks] = pos ;
	      PeakVal[nPeaks] = val ;
       /* if the cursor is on this peak, say so. */
	      if (xINS == pos ) { ISONPEAK = 1 ; onPeak = nPeaks ; }
           nPeaks++ ;
	     }
	    }
	   }

   if (pktype[i] == 3)
   {
      int val, pos ;
   /* Is a true peak. */
		 pos = pkpos[i] ;
		if ((val = dlum[pos]) >= (double)threshold)
		{
          PeakAt[nPeaks] = pos ; 
	     PeakVal[nPeaks] = val ;
      /* if the cursor is on this peak, say so. */
		 if (xINS == pos) { ISONPEAK = 1 ; onPeak = nPeaks ; }
	      nPeaks++ ;
        }
   }
  }
 } // end of if (!huesat)
 else   // we are working with a coloured image
 {		// let's smooth the hue graph

  /* running mean of 3 smoothing,
     done scansmooth times over. */
  for ( j = 0 ; j < scansmooth ; j++ )
  {
   { 
    dhue[0] = (2*hue[0] + hue[1]) / 3 ;				          // first
    dhue[span - 1] = (hue[span - 2] + 2*hue[span - 1]) / 3 ;  // final

	// the others
    for ( i = 1 ; i < span - 1 ; i++ )
    dhue[i] = (hue[i-1] + hue[i] + hue[i+1]) / 3 ;
   }
    for ( i = 0 ; i < span ; hue[i] = dhue[i++] ) ;
  } 
 }
}

/***********************************************************
   This version of TrackSide() works entirely within the
   image RGB buffer. It relies on the use of ScanRGBLine(),
   which returns the PeakAt[] values as horizontal peak-
   positions in the RGB buffer inset, rather than on screen.

 This function works on a single line of the RGB buffer; the
 line-stepping takes place in the Bud Measurement Window Proc.

(17/02/2001 Floating point ops not necessary and eliminated.)
 ***********************************************************/
int TrackRGBProfile(
			     int force,
		         int seek    // the seek half-interval in pixels
		        )
{
    int i, j, k, u, V ;
    int Peakidx[50], PeakFound[50] ;
	int TopPeak, EdgePeak ;
  POINT client ;
 static s, lolim, hilim, W, mindist ;

 if ( force )
 {
   // Don't autotrack. Force wholly manual tracking.
   // Just return the client-relative x position of the mouse.

	 return Xms ;
 }
 else
 {
        client.x = Xms ;
        client.y = Yms ;

// define the seek limits and keep the
// seek interval in the inset (and on-image)

		 lolim = xINS - seek ;
	 if (lolim < 0)  lolim = 0 ;
	     hilim = xINS + seek ;
	 if (hilim > ws) hilim = ws ;

	 // Find all the peaks in the seek interval
	 for ( j = 0, u = 0 ; j < nPeaks ; j++ )
	 {
		 // Note and count included peaks
		 if (
			 ( (s = PeakAt[j]) >= lolim ) && ( s <= hilim )
			)
			 Peakidx[u++] = j ;	  // line-relative index of included peak
	 }

	// If there is at least one peak in seek interval
	if ( u > 0 )	
	{
	 // If we have more than one peak in the seek interval, use
	 // the position of highest peak, or, if two or more peaks
	 // tie for highest, use the position of the peak closest
	 // to the mouse cursor.

	 if (u > 1)  // We have more than one peak in the seek interval
	 {
		// look for the highest peak
		 for ( i = 0, k = 0, TopPeak = 0 ; i < u ; i++ )
		 {
			 if ((V = PeakVal[Peakidx[i]]) > TopPeak)
			 {
				 TopPeak = V ;

			 // If we get a new high peak, then all previous peaks
			 // must have been smaller than the new, even if they
			 // were equal to each other. Restart count of equal
			 // peaks.

			     k = 0 ;
			 }

			 if ( V == TopPeak)

			// We have a new peak. If it is not the first,
			// then it is equal to the highest peak so far, and
			// we have a further equal peak.

				 PeakFound[k++] = Peakidx[i] ;
		 }

		 if (k > 1) // We have more than one equal peak.
		 {
		 // In the set of included, equal peaks, find the peak
		 // with the least distance from the mouse cursor.

		  for ( i = 0, mindist = 32000 ; i < k ; i++ )
	      {
		   if ((W = abs(PeakAt[PeakFound[i]] - xINS)) < mindist)
		   {
		     mindist = W ;
			 // This is the equal peak closest to the cursor
    		EdgePeak = PeakAt[PeakFound[i]] ;
		   }
	      }
		 }
		 else	// This is the single highest peak. Use it.
		 EdgePeak = PeakAt[PeakFound[0]] ;
	}
	 else	 // This is the only peak in the seek interval. Use it.
    	    EdgePeak = PeakAt[Peakidx[0]] ;
   }
   else // There is no peak in the seek interval. 
	    // Assign negative value as flag.

		       EdgePeak = -2 ;

	 // Assign found peak position to cursor position
     // for current and next line, or retain old 
     // cursor position if no peak found.

   if (EdgePeak >= 0)
   {
	// get position of peak in the on-screen image
	// relative to left client border.
	 EdgePeak = MulDiv(EdgePeak, bimwid, ws) + rcimg.left ;
    // position the cursor on the screen image.
	 client.x = EdgePeak ;

	// convert client cursor position to screen co-ordinates
	 ClientToScreen(hWndBud,&client) ;

	// Move the cursor to the latest edge peak position.
	 SetCursorPos(client.x, client.y) ;
   }
   // else we have lost the profile.

   // send back client-position of found edge peak,
   // or the negative flag indicating no peak found.

      return EdgePeak ;
  }
}

//************************************************************
//             Details of the Measurement Grid.
//************************************************************
void MeasureGrid(LPMEASURE M)
{
  	 int i, s ;
LPBUDRESULTS B ;
  double xb, yb, xt, yt ; // poles
  double bl ;			  // bud length in i.u.
  double xl,yl ;          // level cut of axis
  double c,b ;            // intercepts
  double ma, ml ;         // gradients
  double xstep, ystep ;   // steppers
  double u, v ;           // temporary variables

   B = pBudResults ;
   B->BudTopPoleX = xt = M->iTopPole.x ;  // do some transfers
   B->BudTopPoleY = yt = M->iTopPole.y ;
   B->BudBotPoleX = xb = M->iBotPole.x ;
   B->BudBotPoleY = yb = M->iBotPole.y ;

  u = xt - xb ;
  v = yt - yb ;
  if (u == 0.0)	       // trap division by zero
     ma = v * 1.0e10 ; // that is, supply signed humungous number.
  else
     ma = v / u ;	                      // gradient of bud axis
  B->BudTilt   = itan(v, u) ;			  // tilt of bud in radians
                                          // (itan() copes with zero divisor)
  B->BudLength = bl = sqrt(u*u + v*v) ;	  // bud length in image units
   c = yt - ma * xt ;			          // intercept of bud axis
  ml = -1.0/ma ;				          // gradient of a measure level
  
  M->iAxisGradIcept.x = ma ;			  // record axis basics
  M->iAxisGradIcept.y = c ;

  if (GrowthMeasure)
  {
	    s = Levels/2 + 1 ;
   growth = -log(1.0 / (FirstFrac + 0.5) - 1.0) ; // the coefficient
  }
  else
  {
    xstep = u /(double)(Levels + 1 ) ;
    ystep = v /(double)(Levels + 1 ) ;
  }

  for (i = 1 ; i <= Levels ; i++)  // for each level
  {
	if (GrowthMeasure)
	{
		double n, d ;

		 n = (double)(s - i) ;
		 d = 1.0 + exp(growth * n) ;
		
		xl = u / d + xb ;		   // i'th axis cut (growth).
		yl = v / d + yb ;
	}
	else   // is linear height distribution
	{
	 xl = (double)i * xstep + xb ; // i'th axis cut (linear). 
	 yl = (double)i * ystep + yb ; 
	}
	 
	 M->iAxisCuts[i].x = xl ;	   // Cuts ARE recorded in the struct.
	 M->iAxisCuts[i].y = yl ;	   // I'd forgotten. Great! Use in Lambda() ;
	 
	 b = yl - ml * xl ;            // i'th intercept
	 
	 M->iLevGradIcepts[i].x   = ml ;
	 M->iLevGradIcepts[i].y   = b ;
  }													  
}


/***********************************************************************
   
	         Find Lambda, and the Mean Radius Deviation
			 for the left or right sides of the bud, or
			 for both sides taken together.

   Two sorts of lambda and their corresponding least MRDs are delivered
   to the current bud results struct.

   (N.B. For this to work, there must be an odd number of levels.)
 ***********************************************************************/
void Lambda( int side )
{
    LPMEASURE M ;
 LPBUDRESULTS B ;
 int		i, j, t, middle, best_at ;
 double		mh, mdi, plam, sw, w, h, m, z, k, g ;
 double		sx, sy, sx2, sxy, sumx, sumy, sk, sg ;
 double		L, pL, rL, rlam, wee ;
 double		d, dd, dt, ht, di, hi, ee, dev, tdev ;
 double     dX, dY ;
 double     xb, yb, xt, yt ;  // Poles
 double     ipd, u, v ;
 double     levs_used ;

		 M = pMeasure ;
		 B = pBudResults ;

	 xb = M->iBotPole.x ;  // bottom pole (x,y) in i.u.
	 yb = M->iBotPole.y ;
	 xt = M->iTopPole.x ;  //    top pole (x,y) in i.u.
	 yt = M->iTopPole.y ;
	ipd = sqrt(pow(xt-xb,2.0) + pow(yt-yb,2.0)) ; // interpole distance in i.u.

    middle = (Levels+1)/2 ;

   /* initialise */

    switch(side)
    {
	case BOTH:  mdi = M->iDiameter[middle] ; break ;
	case LEFT:  mdi = M->iLeftRad[middle] ;	 break ;
	case RIGHT: mdi = M->iRightRad[middle] ; break ;
	}

	  mh = 0.5 ;			   // true for both growth and linear
	plam = sw = 0.0 ;
	  sx = sy = sx2 = sxy = sumx = sumy = sk = sg = 0.0 ;
	hiXo = hiYo = hiiL = -1.0e10 ;
	loXo = loYo = loiL =  1.0e10 ;

   // lambda calculations
	   for ( j = 1, levs_used = 0.0 ; j <= Levels ; j++ )
		{
		   double x, y, q ;

		   if (GrowthMeasure)
		   {
		    x = M->iAxisCuts[j].x ;
		    u = x - xb ; 
		    y = M->iAxisCuts[j].y ;
		    v = y - yb ;
		    q = sqrt(u*u + v*v) ;
		   }

		   switch(side)
		   {
		   case BOTH:  di = M->iDiameter[j] ; break ;
		   case LEFT:  di = M->iLeftRad[j] ;  break ;
		   case RIGHT: di = M->iRightRad[j] ; break ;
		   }

		 if (GrowthMeasure)
		 Ho[j] = h = fHyts[j] = q / ipd ;
		 else
	     Ho[j] = h = (double)j/(double)(Levels + 1) ;// fractional height

		 Yo[j] = m = log(di/h) ;           // NULL value on upper limb
		 Xo[j] = z = log(di/(1.0 - h)) ;   // NULL value on lower limb

		 // find least and largest NULL Xo and Yo values
		  hiYo = ( Yo[j] > hiYo ) ? Yo[j] : hiYo ;
		  loYo = ( Yo[j] < loYo ) ? Yo[j] : loYo ;

		  hiXo = ( Xo[j] > hiXo ) ? Xo[j] : hiXo ;
		  loXo = ( Xo[j] < loXo ) ? Xo[j] : loXo ;

		if ( j > 1) // interval lambdas	by Lawrence's convention
		{
		 pBudResults->Xmult[j-1] = dX = Xo[j] - Xo[j-1] ; // this is the    top-limb multiplier
		 pBudResults->Ymult[j-1] = dY = Yo[j] - Yo[j-1] ; // this is the bottom-limb multiplier

		 if (dX == 0.0) // avoid division by zero -- but only just!
		 {
			 double sign ;
			 sign = (dY < 0.0) ? -1.0 : 1.0 ; 
			 iL[j-1] = sign * 1.0e10 ;		// properly signed humungous value
		 }
		 else
		     iL[j-1] = -dY / dX ; // the lambda between level j and level j-1

		 // find least and largest
		    hiiL = ( iL[j-1] > hiiL ) ? iL[j-1] : hiiL ;
		    loiL = ( iL[j-1] < loiL ) ? iL[j-1] : loiL ;
		}

	   if (IncludeLev[j])
	    {
		   levs_used++ ;

		   sumx += dX ; // sum of included multipliers for    top limb
		   sumy += dY ; // sum of included multipliers for bottom limb

		     w = fabs(log(h/(1.0 - h))) ; // weighting
		    sw += w ;					  // current sum of weightings

		// weighted projective Lambda for j'th height

		if (j != middle)                  // omit middle height
		plam += w*(k=log(di*mh/(mdi*h))) /
		          (g=log(mdi*(1.0-h)/((1.0-mh)*di))) ; // sum of weighted lambdas

		sk += k ; sg += g ;

		sx += m ; sy += z ;				  // Regression sums
		sx2 += m * m ; sxy += m * z ;
		}
       }

	// projective and regression lambdas

		plam /= sw ; // weighted mean

					// means of included multipliers		 
		pBudResults->meanXmult = sumx/levs_used ; // on    top limb
		pBudResults->meanYmult = sumy/levs_used ; // on bottom limb

		switch(side)
		{
		case BOTH:  pBudResults->DiamProjLambda  = plam ; break ;
		case LEFT:  pBudResults->LeftProjLambda  = plam ; break ;
		case RIGHT: pBudResults->RightProjLambda = plam ; break ;
		}
		pL = plam/(1.0 + plam) ;

		rlam = (sxy - sx*sy/levs_used)/(sx2 - sx*sx/levs_used) ;
		rlam = -1.0 / rlam ;

		switch(side)
		{
		case BOTH:  pBudResults->DiamRegrLambda  = rlam ; break ; 
		case LEFT:  pBudResults->LeftRegrLambda  = rlam ; break ; 
		case RIGHT: pBudResults->RightRegrLambda = rlam ; break ;
		}
		rL = rlam/(1.0 + rlam) ;

	// the MRDs

		for ( j = 0 ; j < 2 ; j++ )
		{
			double sumofsq, sdv ;

		  L = j ? rL : pL ;

		for ( t = 1, wee = 1000.0 ; t <= Levels ; t++ )
		{
			switch(side)
			{
			case BOTH:  dt = M->iDiameter[t] ; break ;
			case LEFT:  dt = M->iLeftRad[t] ;  break ;
			case RIGHT: dt = M->iRightRad[t] ; break ;
			}

		if (GrowthMeasure)
		  ht = fHyts[t] ;
		else
		  ht = (double)t / (double)( Levels + 1 ) ;

		  for ( i = 1, tdev = 0.0 ; i <= Levels ; i++ )
		  {
			  switch(side)
			  {
                case BOTH:  d = M->iDiameter[i] ; break ;
				case LEFT:  d = M->iLeftRad[i] ;  break ;
				case RIGHT: d = M->iRightRad[i] ; break ;
			  }
		if (GrowthMeasure)
			 hi = fHyts[i] ;
		    else
		     hi = (double)i / (double)( Levels + 1 ) ;
		     ee = log( ht * (1.0-hi) / ( hi * (1.0-ht) ) ) ;
		     dd = (dt / ht) * exp( L * ee ) * hi ; // predicted diameter or radius

			 if ( !IncludeLev[i] ) d = dd ;	       // use predicted at excluded height
		     tdev += 100.0 * fabs( dd - d ) / d ;  // accumulated deviation (%)
		  }

		  dev = tdev/(double)Levels ;			   // mean deviation

		  if ( dev < wee)
		  {
			    wee = dev ;
			best_at = t ;
		  }
		}

		// recover the "best_at" level for this pass

		   t = best_at ;
	    
	    // record it
	
switch(side)
	{
case BOTH:	if (j) pBudResults->BRegrBestAt = t ;
	            else 
				   pBudResults->BProjBestAt = t ;
	        break ;
case LEFT:  if (j) pBudResults->LRegrBestAt = t ;
	            else 
				   pBudResults->LProjBestAt = t ;
	        break ;
case RIGHT:	if (j) pBudResults->RRegrBestAt = t ;
	            else 
				   pBudResults->RProjBestAt = t ;
	        break ;
	}

		 // Find and record deviation at each level
		 // on the basis of the "best_at" level.

			switch(side)
			{
			case BOTH:  dt = M->iDiameter[t] ; break ;
			case LEFT:  dt = M->iLeftRad[t] ;  break ;
			case RIGHT: dt = M->iRightRad[t] ; break ;
			}

		 if (GrowthMeasure)
			ht = fHyts[t] ;
		   else
			ht = (double)t/(double)(Levels + 1) ;

		for ( i = 1, sumofsq = 0.0 ; i <= Levels ; i++ )
		  {
			double dv ;
			  switch(side)
			  {
                case BOTH:  d = M->iDiameter[i] ; break ;
				case LEFT:  d = M->iLeftRad[i] ;  break ;
				case RIGHT: d = M->iRightRad[i] ; break ;
			  }

		if (GrowthMeasure)
			 hi = fHyts[i] ;
		    else
		     hi = (double)i / (double)( Levels + 1 ) ;
		     ee = log( ht * (1.0-hi) / ( hi * (1.0-ht) ) ) ;
		     dd = (dt / ht) * exp( L * ee ) * hi ;

			 if ( !IncludeLev[i] )  d = dd ;
		    dev = 100.0 * (dv = fabs( dd - d ) / d) ;

	   sumofsq += dv * dv ; 

			switch (side)
			{
			case BOTH: if (j)
						   pBudResults->BRegrDev[i] = dev ;
				        else
						   pBudResults->BProjDev[i] = dev ;
				break ;
			case LEFT: if (j)
						   pBudResults->LRegrDev[i] = dev ;
				        else
						   pBudResults->LProjDev[i] = dev ;
				break ;
			case RIGHT:if (j)
						   pBudResults->RRegrDev[i] = dev ;
				        else
						   pBudResults->RProjDev[i] = dev ;
				break ;
			}
		  }

		  // standard error (%)
		sdv = 100.0 * sqrt(sumofsq / (double)Levels) ; 

		  // Record Standard Errors

		     switch (side)
			 {
			 case BOTH:  if (j)
							 DRegrSD = sdv ;
				         else
							 DProjSD = sdv ;
				 break ;
			 case LEFT:  if (j)
							 LRegrSD = sdv ;
				         else
							 LProjSD = sdv ;
				 break ;
			 case RIGHT: if (j)
							 RRegrSD = sdv ;
				         else
							 RProjSD = sdv ;
				 break ;
			 }

		  // Record "Best" MRDs

		     switch (side)
			 {
			 case  BOTH: if (j)
							 pBudResults->DiamRegrMRD  = wee ;
				          else 
							 pBudResults->DiamProjMRD  = wee ;
			              break ;
			 case  LEFT: if (j)
							 pBudResults->LeftRegrMRD  = wee ;
				          else 
							 pBudResults->LeftProjMRD  = wee ;
						  break ;
			 case RIGHT: if (j)
							 pBudResults->RightRegrMRD = wee ;
				          else
							 pBudResults->RightProjMRD = wee ;
						  break ;
			 }
		}
} /* end of Lambda() */

void PathCurve( HWND hWnd, int side, int style, HPEN Pen )
{
	      int i, j, passes ;
	   static px1, py1, px2, py2 ;
static double first = -20.0 ;
static double last  =  20.0 ;
static double step  =   0.1 ;
	   double x, y, L, c ;
	   double a, b, r, h, u ;
	   double hr1, hr2, ra1, ra2, coef, rshear ;
	   double tilt, length, cs, sn ;
	   double xb, yb ;  // of low pole.
	   double xx, yy ;  // intermediates.
	   double imwid ;
	     RECT rc ;
    LPMEASURE M  ;
 LPBUDRESULTS B ;
 
	  M = pMeasure ;
	  B = pBudResults ;
   
   tilt = pBudResults->BudTilt - pi/2.0 ;
     cs = cos(-tilt) ;
	 sn = sin(-tilt) ;
 length = pBudResults->BudLength ;
     xb = pBudResults->BudBotPoleX ;
     yb = pBudResults->BudBotPoleY ;
   coef = length /(double)(Levels + 1) ;

			 // include pole heights automatically
			 IncludeLev[0] = IncludeLev[Levels+1] = 1 ;

	 switch(side)
	 {
	 case LEFT:  i = (style == PROJ)? B->LProjBestAt :	   B->LRegrBestAt ;
		         x = M->iLeftRad[i] ;
		         L = (style == PROJ)? B->LeftProjLambda :  B->LeftRegrLambda ;
				 passes = 1 ;
		 break ;
	 case RIGHT: i = (style == PROJ)? B->RProjBestAt :	   B->RRegrBestAt ; 
		         x = M->iRightRad[i] ;
		         L = (style == PROJ)? B->RightProjLambda : B->RightRegrLambda ;
				 passes = 1 ;
		 break ;
	 case BOTH:  i = (style == PROJ)? B->BProjBestAt :	   B->BRegrBestAt ;  
		         x = M->iDiameter[i] ;
		         L = (style == PROJ)? B->DiamProjLambda :  B->DiamRegrLambda ;
				 passes = 2 ;
		 break ;
	 }

	 // Find intercept. 
	 
	 L = -1.0 / L ;			// slope first!

	 if (GrowthMeasure)     // is growth: use pre-calculated fractional heights
	 u = fHyts[i] ;
	 else					// is linear: calculate them now
	 u = (double)i /(double)(Levels + 1) ;

	 c = log( u / (1.0 - u) ) - (L - 1.0) * log( x / u ) ;

	for ( i = 0 ; i < passes ; i++) // if case BOTH, do twice
	{
	// Find "Null-level" ordinates. Convert to "First-Level".
	 
	 for (x = first ; x <= last ; x += step)	// "Null" x
	 {
		 y = L * x + c ;			  //"Null" y
		 a = exp(x) ;		          // on top limb
		 b = exp(y) ;		          // on bottom limb
		 r = a * b / (a + b) ;        // radius or diameter
		 h = length * b / ( a + b ) ; // height on bud axis

		 if (matchbend && BOTH)
		 {
			 int e, HIPOLE, LOPOLE, level[MAXLEVELS + 2] ;

			 LOPOLE = 0 ;
			 HIPOLE = Levels + 1 ;
			 level[LOPOLE] = LOPOLE ;
			 level[HIPOLE] = HIPOLE ;
			 if (GrowthMeasure)
			 {
			  fHyts[LOPOLE] = LOPOLE ;
			  fHyts[HIPOLE] = HIPOLE ;
			 }

			 // compile indexed list of included levels
			 for ( j = 0, e = 0 ; j <= HIPOLE ; j++)
			 {
				if (!IncludeLev[j]) continue ;
				level[e++] = j ;
			 }

			  e-- ;	 // e emerges from the above too big by one

			 /*
			  * Run up by twos through the list of included levels.
			  * If the current height for the calculated radius
			  * lies between the two standard levels, set the
			  * radius-start to the inter-level axis before
			  * plotting the radius (i.e., obtain the shear).
			  */

		     for ( j = 0 ; j < e ; j++)
			 {
				 // get pair of standard heights

				 if (GrowthMeasure)
				 {
					 hr1 = length * fHyts[j] ;
					 hr2 = length * fHyts[j+1] ;
				 }
					 else // is linear measure
				 {
			       hr1 = (double)level[j]   * coef ;
				   hr2 = (double)level[j+1] * coef ;
				 }

				// Is the current height between them?

			    if ( h > hr1 && h <= hr2 )
			    {
				  // Yes, it is. Calculate the local axis.
				  // from the measured axis radii (which
				  // are zero at the top and bottom poles)

				 ra1 = ( level[j]   == LOPOLE ) ? 0.0 : AxisRadius[level[j]  ] ;
				 ra2 = ( level[j+1] == HIPOLE ) ? 0.0 : AxisRadius[level[j+1]] ;

				 // Calculate the required shear.

			  rshear = ra1 + (h - hr1) * (ra2 - ra1)/(hr2 - hr1) ;
				}
			 }
		 }
		  else rshear = 0.0 ;
		 
	 // Shift and rotate to match image.

	 switch (side)
		 {
		 case LEFT:
		r *= -1.0 ;                   // draw to left
			 break ;

		 case BOTH:
		r /= 2.0 ;	            // half-diameter each way from mid-line.
		if ( i ) r *= -1.0 ;    // draw to left on second pass
		r += rshear ;			// use actual mid-line as axis (apply shear)
			 break ;

		 case RIGHT:  
		 default:
			 break ;
		 }

 		xx = r * cs + h * sn  + xb;		  // anti-rotate ("unpan")
		yy = h * cs - r * sn  + yb;

		// Convert to client

		if (hWnd == hWndBud ) // draw PC on bud in bud window
		{
			imwid = (double)bimwid ;
			   rc = rcimg ;
		}

		if (hWnd == hWndRslt) // draw PC on bud in Results window
		{
			imwid = (double)rimwid ;
			   rc = rcresimg ;
		}

		px2 = rc.left   + (int)(imwid * xx) ; 
		py2 = rc.bottom - (int)(imwid * yy) ;
		// Draw the Curve.
		if (x == first) { px1 = px2 ; py1 = py2 ; }
		Draw(hWnd, px1, py1, px2, py2, Pen) ;
		px1 = px2 ; py1 = py2 ;
	 }
	}
}

// *********************************************************************
// Draw trial path curve on measurement image for better pole placing.
// *********************************************************************

void TrialPC(HWND hWnd,	    // Window to draw in
			double Lam,		// Trial Lambda
			double Rmid,	// Trial Mid-height Radius in I.U.
	        double x1, double y1,	// Bottom pole position in I.U.
			double x2, double y2,	//    Top pole position in I.U.
	        HPEN pen)
{
	      int i, Temp ;
	   static px1, py1, px2, py2 ;
static double first = -20.0 ;
static double last  =  20.0 ;
static double step  =   0.1 ;
	   double bimwid, len, u, v ;
	   double tilt, sn, cs, xx, yy ;
	   double L,  a,  b,  c,  x,  y,  r,  h ;
static  POINT plot1, plot2 ;

   bimwid = (double)(rcimg.right - rcimg.left) ;
     tilt = itan(v = (double)(y2-y1),u = (double)(x2-x1)) - pi/2.0 ;
	   sn = sin(-tilt) ;
	   cs = cos(-tilt) ;
      len = sqrt( u*u + v*v ) ;

//Trial PC
	    L = -1.0 / Lam ;					// slope
	    c = (1.0 - L) * log(2.0 * Rmid) ;   // intercept

  for ( i = 0 ; i < 2 ; i++ )
  {

	for ( x = first ; x <= last ; x += step ) // "Null" x
	{
// Trial PC

		 y = L * x + c ;			  // "Null" y
		 a = exp(x) ;		          // on bottom limb
		 b = exp(y) ;		          // on top limb
		 r = a * b / (a + b) ;        // radius or diameter
		 h = len * b / ( a + b ) ;    // height on bud axis
		 
		 if (i) r *= -1.0 ;		  // draw to left on 2nd pass

		xx =  r * cs +  h * sn  + x1;  // anti-rotate ("unpan")
		yy =  h * cs -  r * sn  + y1;

		// Convert to Client (i.e. to pixels)

		px2 = rcimg.left   + (int)(bimwid * xx) ; 
		py2 = rcimg.bottom - (int)(bimwid * yy) ;

		// Draw the Curve.

		if (x == first) { px1 = px2 ; py1 = py2 ; }	// old is new
		  Temp = invert ;	                        // store inversion state
		invert = 1 ;                                // force inversion

		// prevent spill from image rectangle.

		plot1.x = px1 ;  // old point
		plot1.y = py1 ;
		plot2.x = px2 ;	 // new point
		plot2.y = py2 ;

		// plot if both points in the
		// image rectangle, else don't.
		// (crude, but what the hell.)

		if (PtInRect(&rcimg,plot1) && PtInRect(&rcimg,plot2))
		Draw(hWnd, px1, py1, px2, py2, pen) ;

		invert = Temp ;	                       // restore inversion state
		   px1 = px2 ; py1 = py2 ;			   // new as old
	}
  }
}


/********************************************************************/
/* Draw a cross. 'arm' is the size in pixels of an arm of the cross */
/********************************************************************/
void DrawCross( HWND hWnd, int inv, int x, int y, int arm, HPEN Pen )
{
    HDC hdc ;
   HPEN oPen ;


      hdc = GetDC( hWnd ) ;
     oPen = SelectObject( hdc, Pen) ; 
   
   if (inv)
   SetROP2(hdc,R2_XORPEN) ;

   MoveToEx( hdc, x - arm, y, NULL ) ;	  // draw cross
   LineTo( hdc, x + arm + 1, y ) ;
   MoveToEx( hdc, x, y - arm, NULL ) ;
   LineTo( hdc, x, y + arm + 1 ) ;
   LineTo( hdc, x, y ) ;
   
   if (inv)
   SetROP2(hdc,R2_COPYPEN) ;
   
   SelectObject( hdc, oPen ) ;
   ReleaseDC( hWnd, hdc ) ;
}

//********************************************************************
//* Draw a small circle.
//********************************************************************
void DrawCircle( HWND hWnd, int inv, int x, int y, int arm, HPEN Pen )
{
    HDC hdc ;
   HPEN oPen ;


      hdc = GetDC( hWnd ) ;
     oPen = SelectObject( hdc, Pen) ; 
   
   if (inv)
   SetROP2(hdc,R2_XORPEN) ;

   Ellipse(hdc, x - arm, y - arm, x + arm, y + arm) ;
   
   if (inv)
   SetROP2(hdc,R2_COPYPEN) ;
   
   SelectObject( hdc, oPen ) ;
   ReleaseDC( hWnd, hdc ) ;
}

void DrawMark( HWND hWnd, int x, int y, int arm, HPEN Pen )
{
    HDC hdc ;
   HPEN oPen ;
    
    hdc = GetDC( hWnd ) ;
   oPen = SelectObject( hdc, Pen) ; 
   
   if (invert)
   SetROP2(hdc,R2_XORPEN) ;

   MoveToEx( hdc, x, y - arm, NULL ) ;		  // draw vertical tick
   LineTo( hdc, x, y + arm + 1 ) ;
   
   if (invert)
   SetROP2(hdc,R2_COPYPEN) ;
   
   SelectObject( hdc, oPen ) ;
   ReleaseDC( hWnd, hdc ) ;
}

void DrawX( HWND hWnd, int x, int y, int arm, HPEN Pen )
{
    HDC hdc ;
   HPEN oPen ;
    hdc = GetDC( hWnd ) ;
   oPen = SelectObject( hdc, Pen) ; 
   
   SetROP2(hdc,R2_XORPEN) ;

   {
   MoveToEx( hdc, x - arm, y, NULL ) ;	      // draw new cross
   LineTo( hdc, x + arm + 1, y ) ;
   MoveToEx( hdc, x, y - arm, NULL ) ;
   LineTo( hdc, x, y + arm + 1 ) ;
   }

   SetROP2(hdc,R2_COPYPEN) ;
   
   SelectObject( hdc, oPen ) ;
   ReleaseDC( hWnd, hdc ) ;
}


void Draw(HWND hWnd, int x1, int y1, int x2, int y2, HPEN Pen)
{
  HDC hdc ;
  HPEN oPen ;

    hdc = GetDC( hWnd ) ;
   oPen = SelectObject( hdc, Pen ) ;

   if (invert)
   SetROP2(hdc,R2_XORPEN) ;

   MoveToEx(hdc, x1, y1, NULL) ;
   LineTo(  hdc, x2, y2) ;
   
   if (invert)
   SetROP2(hdc,R2_COPYPEN) ;

   SelectObject( hdc, oPen ) ;
   ReleaseDC( hWnd, hdc ) ;
}

void DrawPolyLine(HWND hWnd, LPPOINT Poly[], UINT Pts, HPEN Pen)
{
	;
}

//**************************
// Draw Empty Rectangle
// inverted or non-inverted
//**************************
void DrawRect(
	HWND hWnd,
	 int inv,
	 int xlft,
	 int ytop,
	 int xryt,
	 int ybot,
	HPEN Pen
	)
{
   HDC hdc ;
  HPEN oPen ;

    hdc = GetDC( hWnd ) ;
   oPen = SelectObject( hdc, Pen ) ;

   if (inv)
   SetROP2(hdc,R2_XORPEN) ;

	MoveToEx(hdc, xlft, ytop, NULL) ;
	  LineTo(hdc, xryt, ytop) ;
	  LineTo(hdc, xryt, ybot) ;
	  LineTo(hdc, xlft, ybot) ;
	  LineTo(hdc, xlft, ytop) ;

   if (inv)
   SetROP2(hdc,R2_COPYPEN) ;

   SelectObject( hdc, oPen ) ;
   ReleaseDC( hWnd, hdc ) ;
}  // DrawRect()

/********************************************************/
/*             Rubber Line                              */
/********************************************************/
void RubberLine(HWND hWnd, int x1, int y1, int x2, int y2 )
{
	HDC hdc ;
	HPEN Pen, oPen ;

    hdc = GetDC( hWnd ) ;
	Pen = CreatePen(PS_SOLID, 1, RGB(255, 255, 0));
   oPen = SelectObject( hdc, Pen) ; 
   SetROP2( hdc, R2_XORPEN ) ;
   
   MoveToEx( hdc, x1, y1, NULL ) ;
   LineTo( hdc, x2, y2 ) ;
   
   SetROP2( hdc, R2_COPYPEN ) ;
   SelectObject( hdc, oPen ) ;
   DeleteObject(Pen) ;
   ReleaseDC( hWnd, hdc ) ;
} // Rubber line

/********************************************************/
/* Accommodate Window resizing e.g. by dragging borders. */
/********************************************************/
void AdjustDisplays(void)
{  
           int i, j, hBtn, wBtn ;
           int x, y ;
		   int xlimit, ylimit, cWid, cHyt ;
		   int rxlimit, rylimit, rWid, rHyt ;
		 //int xmrg, ymrg, hi, wi ;

 // Minimum Margin sizes--
 // Until there is reason not to do so,
 // treat both windows identically.

 // the measurement window  
 static bwLwrMrg = 60, bwLftMrg = 42 ;
 static bwUprMrg = 57,  bwRytMrg = 5 ;

 // the results window
 static rwLwrMrg = 60, rwLftMrg = 42 ;
 static rwUprMrg = 57,  rwRytMrg = 5 ;

 // Bud Window
 // ~~~~~~~~~~
   GetClientRect(hWndBud, &rcb) ;
             i = MeasureWindow ;

   SetRect(&rctl[Rez],	  // place the image resize control
	       2,
		   rcb.bottom - 17,
		   40,
		   rcb.bottom - 1) ;

 // Set lower and left margins in Inset.
 
     Inset[i].xo = bwLftMrg ;  
     Inset[i].yo = bwLwrMrg ;  

 // Get current client-area width and height.
      
            cWid = (rcb.right - rcb.left) ;
            cHyt = (rcb.bottom - rcb.top) ;

 // Get the current limits to the displayable width and height.
 
            xlimit = cWid - (bwLftMrg + bwRytMrg) ;
            ylimit = cHyt - (bwLwrMrg + bwUprMrg) ;

   if (gotimage) // We have a DDBitmap to display
   {

    // Get the width and height of it.

	   x = ws ;
	   y = hs ;

    // In the first instance, set the Inset width and height to match.
    
         Inset[i].w = x ;
         Inset[i].h = y ;
        
/**
	   If either the height or the width, or both, of the bitmap is
       greater than the limit, reduce the size of the map until the
       larger dimension is within its limit.
       
       If both dimensions are smaller than their limits, increase
       the dimensions until the larger dimension reaches its limit.
       
       In either case, preserve the aspect ratio of the map.
**/
      
     while ( x > xlimit || y > ylimit )
     {
       x -= 1 ;
	   y = MulDiv(x, hs, ws) ;
     }
     

	 while ( x < xlimit && y < ylimit )
     {
       x += 1 ;
	   y = MulDiv(x, hs, ws) ;
     }
	   
	 Inset[i].w = x ;
	 Inset[i].h = y ;

// The bud image RECT in the Bud Window

	SetRect(
			&rcimg,
             bwLftMrg,
	         rcb.bottom - (bwLwrMrg + y),
             bwLftMrg + x,
	         rcb.bottom - bwLwrMrg
			) ;

{
	int left, top, right, bottom ;

	for ( i = Btn80 ; i < Btn86; i++ )
	{
		  left = (i - Btn80) * (48 + 2) + 2 ;
		bottom = rcimg.bottom + 40 ;
		   top = bottom - 18 ;
		 right = left + 48 ;
		SetRect(&rctl[i], left, top, right, bottom) ;
	}
}


// globally available screen-image width and height
	 bimwid = rcimg.right  - rcimg.left ;
	 bimhyt = rcimg.bottom - rcimg.top  ;

	 SetRect(&rcwipe,rcb.left + rctl[Rez].right,
		             rcimg.bottom,
					 rcb.right,
					 rcimg.bottom + 22) ;

		   // Pixel magnification factor, or, the side-size of an
		   // on-screen "apparent pixel" in the Inset, calculated
		   // _after_ the new Inset size is established.

	        pmag = (double)bimwid / (double)ws ;

		   // pmag is also the magnification factor generally

			pBudResults->BudMag = pmag ;
			RecordDimensions() ;

			// Conversion factor DIB bits to pixels, and vice versa

			DIBitsPerPx = ws / Inset[MeasureWindow].w ;

/************************************************
				The  Results Window
 ************************************************/

// The bud image RECT in the Results window

	 GetClientRect(hWndRslt, &rcrslt) ;
               i = ResultsWindow ;

 // Set lower and left margins in Inset.
 
     Inset[i].xo = rwLftMrg ;  
     Inset[i].yo = rwLwrMrg ;  

 // Get current client-area width and height.
      
            rWid = (rcrslt.right - rcrslt.left) ;
            rHyt = (rcrslt.bottom - rcrslt.top) ;

 // Get the current limits to the displayable width and height.
 
            rxlimit = rWid - (rwLftMrg + rwRytMrg) ;
            rylimit = rHyt - (rwLwrMrg + rwUprMrg) ;

   if (gotimage) // We have a DDBitmap to display
   {

    // Get the width and height of it.

	   x = ws ;
	   y = hs ;

    // In the first instance, set the Inset width and height to match.
    
         Inset[i].w = x ;
         Inset[i].h = y ;
         
/**
	   If either the height or the width, or both, of the bitmap is
       greater than the limit, reduce the size of the map until the
       larger dimension is within its limit.
       
       If both dimensions are smaller than their limits, increase
       the dimensions until the larger dimension reaches its limit.
       
       In either case, preserve the aspect ratio of the map.
**/
      
     while ( x > rxlimit || y > rylimit )
     {
       x -= 1 ;
	   y = MulDiv(x, hs, ws) ;
     }
     

	 while ( x < rxlimit && y < rylimit )
     {
       x += 1 ;
	   y = MulDiv(x, hs, ws) ;
     }
	   
	 Inset[i].w = x ;
	 Inset[i].h = y ;

// The bud image RECT in the Results Window

	 			SetRect(
					&rcresimg,
                     Inset[i].xo,
	                 rcrslt.bottom - (Inset[i].yo + Inset[i].h),
                     Inset[i].xo + Inset[i].w,
	                 rcrslt.bottom - Inset[i].yo
					) ;

// globally available screen-image width and height
	 rimwid = rcresimg.right  - rcresimg.left ;
	 rimhyt = rcresimg.bottom - rcresimg.top  ;
   }

  if (Levels == 0) // Filthy hack!!!
  {
	  Levels = dfault ;
	  MessageBox(hWndCtrl,
		        "Measure Levels set to default",
		        "No Measure Levels",
		         MB_ICONEXCLAMATION|MB_OK) ;
  }

// The measure-height selection buttons
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// We have (Levels) heights from which to select, so (Levels) buttons to
// draw in a column to the left of the bud image. The width of this column
// is constant, so the button width is also constant. Let the total
// clearance be 8 pixels, 4 on each side of the column, and the vertical
// clearance between buttons be 2 pixels. There are (Levels - 1) vertical
// clearances.

// 15th July 2001: 12-pixel-wide column inserted
// between button-column and image. Room for more buttons.

     hBtn =((rcimg.bottom - rcimg.top) - 2 * (Levels - 1)) / Levels ;

	 wBtn = rcimg.left - 20 ;				// button width

// Set up button rectangles
	 
	 for ( j = 0 ; j < Levels ; j++ )
	 {
		 rclv[j].top    = rcimg.top    + j * (hBtn + 2) ;
		 rclv[j].left   = 4 ;
		 rclv[j].bottom = rclv[j].top  + hBtn ;
		 rclv[j].right  = rclv[j].left + wBtn ;
     }

// Set up button-column rectangle (used for clearing whole column)

		rccol.left   = rclv[1].left ;
	    rccol.top    = rcimg.top ;
		rccol.right  = rclv[1].right ;
		rccol.bottom = rcimg.bottom ;

// Wiping rect. for region between buttons and image

		rccolrt.left   = rclv[1].right ;
		rccolrt.top    = rcimg.top ;
		rccolrt.right  = rcimg.left ;
		rccolrt.bottom = rcimg.bottom ;
   }
  else // Not a bitmap, use limits as defaults.
   {           
     Inset[i].w = xlimit ;
     Inset[i].h = ylimit ;
   }

// Scan-line window
// ~~~~~~~~~~~~~~~~
   
   GetClientRect(hWndScan,&rcscan) ;

   cHyt = rcscan.bottom - rcscan.top ;
   cWid = rcscan.right - rcscan.left ;

   i = Scan1Window ;
   Inset[i].xo = 30 ;  
   Inset[i].yo = cHyt /2 + 10 ; 
   Inset[i].w  = cWid - (Inset[i].xo +  5) ;
   Inset[i].h  = cHyt - (Inset[i].yo + 20) ;

   i = Scan2Window ;
   Inset[i].xo = 30 ;  
   Inset[i].yo = 30 ; 
   Inset[i].w  = cWid - (Inset[i].xo + 5) ;
   Inset[i].h  = cHyt - (Inset[i].yo + cHyt/2 + 5) ;
   
   SetRect(&rcscb,
           0,
		   0,
		   rcscan.right,
		   20 ) ;

   SetRect(&rcscl,
	       0,
		   rcscb.bottom,
		   Inset[i].xo,
		   rcscan.bottom ) ;

   // Move the gain and threshold scrollbars
   MoveWindow(hScrGain,2,rcscan.bottom - 110,12,80,TRUE) ;
   MoveWindow(hScrTh, 15,rcscan.bottom - 110,12,80,TRUE) ;

}


/*********************************************************************/
/* Of the Path, retain only the Filename and, if any, the Extension. */
/*********************************************************************/
char * DropPath(char * fn)
{
   int i, j, len ;
  char c ;
  static char str[100] ;
   
   len = strlen(fn) ;
   // pick up only the chars after the rightmost backslash
   for ( i = 0, j = 0 ; i < len ; i++ )
   {
     if ( ( c = fn[i] ) == '\\')
     j = 0 ;
     else
     str[j++] = c ;
   }
     str[j] = '\0' ;
     
     return str ; 
}

/************************************************************
  Substitute a new file extension for the existing extension.
 ************************************************************/
char * AddExt(char * fn, char * ext )
{
	char c ;
	static char str[255] ;
	 int i, len ;

	len = strlen( fn ) ;
	  i = 0 ;
	while ((c = fn[i]) != '.' && i < len  ) str[i++] = c ;
	str[i] = '\0' ;
	strcat(str, ext) ;
		
	return str ;
}

/************************************************************
  Get File name, drop extension.
 ************************************************************/
char * DropExt(char * fn)
{
	char c ;
	static char str[256] ;
	 int i, len ;

	len = strlen( fn ) ;
	  i = 0 ;
	while ((c = fn[i]) != '.' && i < len  ) str[i++] = c ;
	str[i] = '\0' ;
		
	return str ;
}

 /***********************
   Get File Extension.
  ***********************/
char * GetExt(char * fn)
{
	static char ext[10] ;
	 int i, j ;

	 if (strstr(fn, ".") == NULL)
	 {
		ext[0] = '\0' ;
		return ext ; // there is no extension
	 }

	  i = j = 0 ;
	while ( fn[i] != '.' && fn[i] != '\0') i++ ;
	while (fn[i] != '\0') ext[j++] = fn[i++] ;
	ext[j] = '\0' ;
		
	return ext ;
}

//********************************************************
// Get the path from a fully qualified path\filename.ext
// by copying all to and including the rightmost backslash
//********************************************************
char * GetMyPath(char * fn)
{
	static char path[256] ;
	char c ;
	 int n, i ;

	if (strstr(fn, "\\") == NULL) // if there is no backslash in the string, there is no path
	{
		path[0] = '\0' ;
		return path ; // there is no path, so return an empty string of zero length
	}
	n = strlen(fn) ;
	while ((c = fn[n]) != '\\') n-- ;				// run back to find the rightmost backslash
	for (i = 0 ; i <= n ; i++) path[i] = fn[i] ;	// copy chars of path to path[] 
	path[i] = '\0' ;								// zero terminate

	return path ;
}

// ***************************************************
//
//					ParseBudID()
//
// Separate the components of the Bud-instance I.D.
//
//		30 July 2004:
// besides image files, now detects and validates INI files.
//
//		10th August 2004
// now also detects and validates TRK and DAT files.
//
// returns zero on any non-valid file
//
// returns IMG on valid image file
// returns INI on valid INI file.
// returns TRK on valid TRK file.
// returns DAT on valid DAT file.
//
// places the details in the BUDID struct &B --
//
// path,
// prefix,
// suffix,
// epoch (date - and time of day if present.) 
// extension (see also returns above)
//
// Validity relies on the bud files being
// named according to the convention ---
//
//       prefix_dddddd[suffix].extension
//
//	where d is a digit character in the range '0' to '9'.
//
//		e.g.  ka_131099test.jpg
//
// The underscore followed by three digit pairs are required.
// The suffix is optional.
//--------------------------------------------------------------------
//		28th March 2002:
//  If first six chars of the suffix are numeric, and in valid ranges,
//  they are taken as giving the time-of-day of the Instance, to the second.
//  e.g.
//	ka_dddddd132445.jpg implies time-of-day was 13 hrs 24 mins 45 seconds
//--------------------------------------------------------------------
//		21st January 2003;
//  If a char after the underscore, but before the suffix, is non-numeric
//  it cannot be part of a date, so the file is rejected as non-standard
//  without further processing.
// ***************************************************
int ParseBudID( char * BudID, LPBUDID B)
{
	 int i, j, len, len2, len3, len4, ispath, retval, dim ;
	char c ; // path[255] ;
	static char string[80], Rest[80] ;

	ispath = strlen(strcpy(B->Directory, FetchPath(BudID))) ;

	// get the extension
	if (strlen(strcpy(B->Extension, GetExt(BudID)))) // if there is an extension, first copy to the info struct
	{
	// check for allowed extensions
	if (!strcmp(_strlwr(B->Extension), ".ini")) {retval = INI ; goto perhaps ;}
	if (!strcmp(_strlwr(B->Extension), ".trk")) {retval = TRK ; goto perhaps ;}
	if (!strcmp(_strlwr(B->Extension), ".dat")) {retval = DAT ; goto perhaps ;}
	if (!strcmp(_strlwr(B->Extension), ".jpg")
			||
		!strcmp(_strlwr(B->Extension), ".bmp"))
		{
			retval = IMG ; // is an image file

		// path or no path, drop the extension for what follows.
perhaps:	if (ispath)
				strcpy(string, DropPath(DropExt(BudID))) ;	// there is a path, remove it and extension,
			else											// no path, just drop the extension
				strcpy(string, DropExt(BudID)) ;  
		}
	  else // has no extension 
		   // or has the wrong kind,
		   // or has wrong image format,
		   // so reject the file
					return 0 ; 
	}

	// copy the file name (without extension) to the info struct, and get its length
		len = strlen(strcpy(B->InstName, string)) ;

// now we parse the thing for prefix and sampling epoch. 

	  // pick up all until underscore, to pick out the prefix 
	   i = j = 0 ;
	   while ((c = string[i++]) != '_' && i <= len) B->Prefix[j++] = c ;
	   
	   B->Prefix[j] = '\0' ;		// zero terminate the prefix string

	   len2 = strlen(B->Prefix) ;	// and get the prefix string's length

	   if (len2 == 0 || len2 >= len)// if no underscore found,
									// or prefix has zero length (underscore is first character)
									// is invalid file name,
									// reject
											return 0 ;
	  // copy the rest to own string
	   j = 0 ;
	   while (i < len) Rest[j++] = string[i++] ;

	  // make sure is asciiz.  
	   Rest[j] = '\0' ;

	  // get its length
	   len3 = strlen(Rest) ;

	   if (len3 < 6)				// too short
									// is not valid in any event
									// reject
											return 0 ;
	   
	  // get chars from Rest[] two by two, like Noah.
		// check if char digit, reject image/ini/etc if not.
		//(also check for valid civil date ranges),
		  // then get suffix, if any.
			// if suffix, then check if it is a time.
				// if no suffix, or is silly time, default to Noon.

	   // the two Year digits
	   for (i = 4, j = 0 ; i < 6 ; i++)
	   {
	     c = Rest[i] ;
	     if (!isdigit((int)c))					// not digit,
												// so can't be a year;
												// reject
														return 0 ;

		 B->szBudYr[j++] = c ;				// else get the digit as a char
	   }
	   B->szBudYr[j] = '\0' ;				// zero terminate the string
	   B->BudYr = atoi(B->szBudYr) ;		// convert to integer and record in info struct

	   if (B->BudYr < 0)						// negative:
												// can't be a year:
												// reject
														return 0 ;
	   // expand to full year
	   if (B->BudYr < 80) B->BudYr += 2000 ; else B->BudYr += 1900 ;
	   _itoa(B->BudYr, B->szBudYr, 10) ;	// convert full year to string and record


	   // the two Month digits
	   for (i = 2, j = 0 ; i < 4 ; i++)
	   {
	     c = Rest[i] ;
	     if (!isdigit((int)c))					// not digit,
												// so can't be a month;
												// reject
														return 0 ;

		 B->szBudMon[j++] = c ;				// else get the digit as a char
	   }
	   B->szBudMon[j] = '\0' ;				// zero terminate the month string
	   B->BudMon = atoi(B->szBudMon) ;		// convert to integer and record in info struct

	   if (B->BudMon <= 0 || B->BudMon > 12)	// is zero or negative
												// or greater than 12:
												// can't be a month:
												// reject
														return 0 ;
	   // else get days in month

	   dim = dimonth[B->BudMon] ;
	   if (IsLeapYr(B->BudYr) && B->BudMon == 2) dim++ ; // if leap year and february, add one to dim


	   // the two Day digits
	   for (i = 0, j = 0 ; i < 2 ; i++)
	   {
	     c = Rest[i] ;
	     if (!isdigit((int)c))					// not digit,
												// so can't be a date; 
												// reject
														return 0 ;

	     B->szBudDay[j++] = c ;				// else get the digit as a char
	   }
	   B->szBudDay[j] = '\0' ;				// zero terminate the day string
	   B->BudDay = atoi(B->szBudDay) ;		// convert to integer and record in info struct

	   if (B->BudDay <= 0 || B->BudDay > dim)	// is zero or negative
												// or greater than the month's range, so
												// can't be a day of any month.
												// reject
														return 0 ;


	   // the Suffix
	   for (i = 6, j = 0 ; i < len3 ; B->Suffix[j++] = Rest[i++]) ;
	   B->Suffix[j] = '\0' ;

	   //			28th March 2002
	   //
	   //		(and 10th Feb 2004: Extended to include Seconds field)
	   //
	   // Allow for possible inclusion in the Bud ID of the time-of-day,
	   // by the 24 hour clock, to the nearest second.
	   //
	   // GMT is assumed - for the moment. GMT/Local-Time detection is planned,
	   // but not yet implemented.
	   //
	   // If no suffix has been appended to the instance ID, then no
	   // Time has, either. If there is a suffix, then if it has fewer
	   // than four characters, it does not contain a Time.
	   //
	   // If the suffix has four or more characters, then if any one of the first four
	   // is non-numeric, the suffix does not contain a Time.
	   //
	   // If the first four characters are numeric, then they _may_ represent a Time.
	   //
	   // If the first two of these four represent a number larger than 24,
	   // or negative, it is not a valid hour.

	   // If the second two represent a number larger than 59, or negative,
	   // it is not a valid number of minutes.
	   //
	   // If the suffix has in fact six or more characters, then if
	   // any of the remaining characters is non-numeric, it is not a number
	   // of seconds.
	   
	   // Otherwise, if the third pair represent a number larger
	   // then 59 or negative, it is not a valid number of seconds.
	   //
	   // Otherwise, a valid Time has _probably_ been appended, and it
	   // will be accepted as such.
	   //
	   // If no Time, or an invalid Time, has been appended, the Time
	   // defaults to noon exactly.
	   //
	   // Because we may now get other than one bud instance per day,
	   // the Bud Workshop must work with the actual epoch, rather
	   // than the civil date, so the Parser now supplies this epoch.

	   len4 = strlen(B->Suffix) ;

	// don't bother if fewer than 4 chars in suffix, as it can't be a time

	   if (len4 < 4) goto notime ;	// but default to exactly noon.

	// are the first two chars of the suffix numeric? (Hour)

	   for ( i = 0, j = 0 ; i < 2 ; i++ ) 
	   {
		   if (!isdigit(c = B->Suffix[i]))
			   goto notime ;	// char is non-numeric, so no Time. Default to noon
		   else					// char is numeric
			   B->szBudHr[j++] = c ;
	   }
	           B->szBudHr[j] = '\0' ; // make asciiz

	// is this a silly number of hours?

		if ((B->BudHr = atoi(B->szBudHr)) < 0 || B->BudHr > 24) goto notime ;
		strcpy(B->szTime, B->szBudHr) ;

	// are the next two chars of the suffix numeric? (Minutes)

	   for ( i = 2, j = 0 ; i < 4 ; i++ )
	   {
		   if (!isdigit(c = B->Suffix[i]))
			   goto notime ;	// char is non-numeric, so no Time. default to noon,
		   else					// char is numeric
			   B->szBudMn[j++] = c ;
	   }
	           B->szBudMn[j] = '\0' ; // make asciiz

	// is this a silly number of minutes?

		if ((B->BudMn = atoi(B->szBudMn)) < 0 || B->BudMn > 59) goto notime ;
		strcat(B->szTime, B->szBudMn) ;

	   if (len4 >= 6) // there may be a Seconds field
	   {
		// are the next two chars of the suffix numeric? (Seconds)
		for ( i = 4, j = 0 ; i < 6 ; i++ )
		{
		   if (!isdigit(c = B->Suffix[i]))
			   goto notime ;	// char is non-numeric, so no Time. Default to noon,
		   else					// char is numeric
			   B->szBudSc[j++] = c ;
		}
	           B->szBudSc[j] = '\0' ; // make asciiz

	 // is this a silly number of seconds?

		if ((B->BudSc = atoi(B->szBudSc)) < 0 || B->BudSc > 59) goto notime ;
		strcat(B->szTime,":") ;
		strcat(B->szTime, B->szBudSc) ;
		}
		goto gotit ;

notime:	{	   strcpy(B->szTime, "1200:00") ;
			   strcpy(B->szBudHr, "12") ;
			   B->BudHr = 12 ;
			   strcpy(B->szBudMn, "00") ;
			   B->BudMn = 0 ;
			   strcpy(B->szBudSc, "00") ;
			   B->BudSc = 0 ;
		}

gotit:	   strcpy(B->FriendlyDate,
		      MakeFriendlyDate(1, B->BudDay, B->BudMon, B->BudYr)) ;

		   strcpy(B->FriendlyTime, B->szTime) ;

	// Julian epoch of this instance
		   {
			   double tep ;
		    tep = ep ;			// hold current ep in case it's a working one
			day = B->BudDay ;
			 mo = B->BudMon ;
			 yr = B->BudYr ;

			 setepoch() ; // julian epoch to nearest day

			 // add in time of day to nearest second 
			 B->JulEp = ep + (
								(double)B->BudHr + 
								(double)B->BudMn / 60.0 + 
								(double)B->BudSc / 3600.0
							 ) / 24.0 ;

			 sprintf(B->szJulEp, "%11.8f", B->JulEp) ;

			 ep = tep ;			// restore current ep
		   }

			   return retval ;	// is a validly named file, return its type 
}

//	*************************************
//       Find words in line of chars.
//   Return pointer to the index'th word.
//  *************************************
char * ParseLine( char line[], int index )
{
  int i, j, k, u ;
  static char * Words[MAXITEMS] ;
  static char indexed[100] ;

  for (i = 0 ; i < MAXITEMS ;
	  Words[i++] = (char *)GlobalAlloc(GPTR, 100 * sizeof(char))) ;

  i = j = k = u = 0 ;

// As long as we have some string..

while (line[i] != '\0')
{
// Ignore whitespace

while ( line[i] <= 32 )  i++ ;

// Copy out darkspace while it lasts. Flag that we're doing this.
 	
while ( line[i] > 32 ) { *(Words[j] + k++) = line[i++] ; u = 1 ; }

if (u)  // No more darkspace for now, but must've just left a word
  {
   *(Words[j] + k) = '\0' ;	// Zero-terminate it. 
     k = 0 ;				// Start again with..
     j++ ;					// ..a new word
	 u = 0 ;				// Cancel flag ready for more whitespace
  }
}
// Um. What if there is no index'th word, i.e., too few words?
// Ok, try this---

if ( j >= index )					// sufficient number of words
   strcpy(indexed,Words[index]) ;	// get the one we want
else								// too few words, so
	indexed[0] = '\0' ;				// send back an empty string

// Ah, but it was empty anyway (because allocated with GPTR), wasn't it ?
// Redundant code! Never mind, leave it.

for ( i = 0 ; i < MAXITEMS ; GlobalFree(Words[i++])) ;

 return (indexed) ; 
}

// *****************************************
//  Find first (oldest) and final (youngest)
//  instances of this bud in the Archive.
//
//    Wanted = 0 => First wanted
//    Wanted = 1 => Final wanted
//    Wanted = 2 =>  Both wanted
//
//  If the wanted items are in the work file,
//  fetch them from there, else search the
//  whole Archive for them, place them in the
//  Work file, then return them.
//
//  16/03/2001: Since the info sought by this 
//  routine is now automatically updated
//  whenever a bud instance is brought into
//  work,the routine should eventually become
//  redundant.  
// *****************************************

int GetFirstandFinal(LPBUDSEARCH sb, int Wanted )
{
 static i, n ;
 static FirstWanted, LastWanted, UserSays ;
 static iImgID, iPfxID ;

// Sort out the options
	switch( Wanted )
	{
	case 0 :
       FirstWanted = 1 ;
	   LastWanted  = 0 ;
	   break ;
	case 1 :
       FirstWanted = 0 ;
	   LastWanted  = 1 ;
		break ;
	case 2:
       FirstWanted = 1 ;
	   LastWanted  = 1 ;
		break ;
	default: return 0 ; // must've been some muddle on the way
	}


	if (!searched)
	{
		char str[300] ;

		sprintf(str,
"The Bud Workshop needs to find and list\n" \
"the validly-named image-files currently\n" \
"on the system.\n\n" \
"Do you wish this to happen now?") ;

	UserSays = MessageBox(NULL, str, "Get Series Dates has no Data.",
			              MB_ICONEXCLAMATION|MB_YESNO) ;

		if (UserSays == IDYES)
		{
			SendMessage(hWndColl, WM_COMMAND, IDM_ARCHIVIST, 0L) ;
			goto proceed ;
		}
		
		return 0 ;
	}

proceed: for (i = 0 ; i < A.iPfxIDs ; i++)
		 {
			 if (!strcmp(sb->Prefix, A.szKnownpfx[i]))
			 {
				 iPfxID = i ; break ;
			 }
		 }

			 n = A.iNumImgperpfx[iPfxID] - 1 ;

			if (FirstWanted)
			{
				iImgID = A.Imgperpfx[iPfxID][0] ;
				ParseBudID(A.szKnownimg[iImgID], Search_ID) ;

				strcpy(sb->szBudDay1, Search_ID->szBudDay) ;
				sb->BudDay1 = atoi(Search_ID->szBudDay) ;

				strcpy(sb->szBudMon1, Search_ID->szBudMon) ;
				sb->BudMon1 = atoi(Search_ID->szBudMon) ;

				strcpy(sb->szBudYr1,  Search_ID->szBudYr) ;
				sb->BudYr1 = atoi(Search_ID->szBudYr) ;

				strcpy(sb->szBudSc1,  Search_ID->szBudSc) ;
				strcpy(sb->szBudMn1,  Search_ID->szBudMn) ;
				strcpy(sb->szBudHr1,  Search_ID->szBudHr) ;
				sb->JulEp1 = Search_ID->JulEp ;

			if (!LastWanted) return 1 ;
			}


			if (LastWanted)
			{
				iImgID = A.Imgperpfx[iPfxID][n] ;
				ParseBudID(A.szKnownimg[iImgID], Search_ID) ;

				strcpy(sb->szBudDay2,Search_ID->szBudDay) ;
				sb->BudDay2 = atoi(Search_ID->szBudDay) ;

				strcpy(sb->szBudMon2, Search_ID->szBudMon) ;
				sb->BudMon2 = atoi(Search_ID->szBudMon) ;

				strcpy(sb->szBudYr2,  Search_ID->szBudYr) ;
				sb->BudYr2 = atoi(Search_ID->szBudYr) ;

				strcpy(sb->szBudSc2,  Search_ID->szBudSc) ;
				strcpy(sb->szBudMn2,  Search_ID->szBudMn) ;
				strcpy(sb->szBudHr2,  Search_ID->szBudHr) ;
				sb->JulEp2 = Search_ID->JulEp ;

			if (!FirstWanted) return 1 ;
			}

	return 1 ;
}

// ******************************************************
//						Inventory().
//
//		4th July 2004:
// first modified to work with the new Archivist
//
//		8th April 2005
// all reference to workfiles removed,
// reference instead to Suites installed. 
// ******************************************************
int Inventory( LPBUDSEARCH sb )
{
// Sections
#define PLmrd 0
#define RLmrd 1
#define Dims  2
#define StDv  3

// Keys
#define P_Ld  0
#define P_Ll  1				
#define P_Lr  2

#define R_Ld  3 
#define R_Ll  4
#define R_Lr  5

#define rStdv  6
#define mStdv  7
#define Levs   8
#define Frmg   9


// indices according to new style
#define LAM   1
#define MRD   3
#define IPD   1
#define TLT   3
#define STD   1

#define D_D   0
#define D_L   1
#define D_R   2


 HFILE hCol ;
 OFSTRUCT of ;
 int k, item ;
 double fEp ;
 static count ;
 int firstonrecord, finalonrecord ;

    static char       string[80] ;
    static char      szCRLF[] = "\r\n" ;
	static char        buff[255] ;
	static char        nbud[10]  ;
	static char         pfx[80]  ;
	static char         sfx[80]  ;
	static char      folder[255] ;
	static char  szWorkName[255] ;
	static char szImageName[255] ;
	static char   szIniName[255] ;
																 // section
	static char * pszSection[] = {"Projective Lambdas & MRDs",	 // 0
		                          "Regression Lambdas & MRDs",	 // 1
						          "Dimensions",					 // 2
	                              "Standard Deviations"}  ;		 // 3

																 // key
	static char     * pszKey[] = {"Pr_Diam","Pr_LRad","Pr_RRad", // 0,1,2
	                              "Rg_Diam","Rg_LRad","Rg_RRad", // 3,4,5
								  "Raw St.Dev.",				 // 6
								  "Mean St.Dev.",				 // 7
	                              "Levels Used",				 // 8
								  "Framing",					 // 9
	                              "LevelA", "LevelB", "LevelC",	 //10,11,12
	                              "LevelD", "LevelE", "LevelF",	 //13,14,15
	                              "LevelG", "LevelH", "LevelI",	 //16,17,18
	                              "LevelJ", "LevelK", "LevelL",	 //19,20,21
	                              "LevelM", "LevelN", "LevelO",	 //22,23,24
	                              "LevelP", "LevelQ", "LevelR",	 //25,26,27
	                              "LevelS", "LevelT", "LevelU",	 //28,29,30
	                              "LevelV", "LevelW", "LevelX",	 //31,32,33
	                              "LevelY", "LevelZ", 		     //34,35
	                              "Level27","Level28","Level29", //36,37,38
	                              "Level30","Level31","Level32", //39,40,41
	                              "Level33","Level34","Level35", //42,43,44
	                              "Level36","Level37","Level38", //45,46,47
	                              "Level39","Level40","Level41", //48,49,50
	                              "Level42","Level43","Level44", //51,52,53
	                              "Level45","Level46","Level47", //54,55,56
	                              "Level48","Level49","Level50", //57,58,59
	                              "Level51","Level52" }  ;		 //60,61

 static char *   section[MAXITEMS] ;
 static char *       key[MAXITEMS] ;
 static  int       index[MAXITEMS] ;
 static  int     sectidx[MAXITEMS] ;
 static  int      keyidx[MAXITEMS] ;
 static  int	  iInsts ;
     LPSUITE	  sui ;

		// The number of instances known to the current prefix 
			iInsts = A.iNumImgperpfx[CurrentPfxID] ;

		// the suite currently assigned for this prefix
			   sui = A.pSuiteperpfx[CurrentPfxID][UseSuite] ;

	// Since the new Archivist has the series dates,
	// and it does not depend on the buds having been
	// seen in the BW, but on whether or not there are
	// instances of the bud somewhere on the system, 
	// we no longer need to get it from the Workfile.

	firstonrecord = finalonrecord = 1 ; // now so by definition

	 first_bud_ep = A.fEarlyEp[CurrentPfxID] ;	// the first epoch of the current prefix
	 final_bud_ep = A.fLaterEp[CurrentPfxID] ;	// the  last epoch of the current prefix

	strcpy(sfx,   sb->Suffix) ;
	strcpy(folder,sb->Directory) ;

	// Tabula Rasa

	// Well, nowadays there is no way for the BW to know if a bud is missing, 
	// since it no longer assumes a strictly regular sampling schedule: it now
	// assumes that the epoch sequence it actually gets is correct and complete.
	// So the bits of code pertaining to absent instances could be removed.

	//	8th April 2005
	// They have been removed!

	         // Start at the first bud
				bud = 0 ;

			 // Sort out the search criteria.
				count = 0 ;

			  if (SRCH & PLAM) // Projective Lambda
			  {
			  	if (SRCH & LDIA) // On diameters
				{
					++count ;
					section[count] = pszSection[PLmrd] ;
					    key[count] = pszKey[P_Ld] ;
					  index[count] = LAM ;	  // corresponding index

					sectidx[count] = PLmrd ;
					 keyidx[count] = P_Ld ;

					if (SRCH & MRDS) // want MRDs
					{
						++count ;
					section[count] = pszSection[PLmrd] ;
					    key[count] = pszKey[P_Ld] ;
					  index[count] = MRD ;

					sectidx[count] = PLmrd ;
					 keyidx[count] = P_Ld ;
					}

				}

				if (SRCH & LLFT) // On left radii
				{
					++count ;
					section[count] = pszSection[PLmrd] ;
					    key[count] = pszKey[P_Ll] ;
					  index[count] = LAM ;	  // corresponding index

					sectidx[count] = PLmrd ;
					 keyidx[count] = P_Ll ;

				   if (SRCH & MRDS)
					{
						++count ;
					section[count] = pszSection[PLmrd] ;
					    key[count] = pszKey[P_Ll] ;
					  index[count] = MRD ;

					sectidx[count] = PLmrd ;
					 keyidx[count] = P_Ll ;
					}
				}

				if (SRCH & LRYT) // On right radii
				{
					++count ;
					section[count] = pszSection[PLmrd] ;
					    key[count] = pszKey[P_Lr] ;
					  index[count] = LAM ;	  // corresponding index

					sectidx[count] = PLmrd ;
					 keyidx[count] = P_Lr ;

					if (SRCH & MRDS)
					{
						++count ;
					section[count] = pszSection[PLmrd] ;
					    key[count] = pszKey[P_Lr] ;
					  index[count] = MRD ;

					sectidx[count] = PLmrd ;
					 keyidx[count] = P_Lr ;
					}
				}
			  }

			  if (SRCH & RLAM)  // Regression Lambdas
               {
			  	if (SRCH & LDIA) // On diameters
				{
					++count ;
					section[count] = pszSection[RLmrd] ;
					    key[count] = pszKey[R_Ld] ;
					  index[count] = LAM ;	  // corresponding index

					sectidx[count] = RLmrd ;
					 keyidx[count] = R_Ld ;

					if (SRCH & MRDS)
					{
						++count ;
					section[count] = pszSection[RLmrd] ;
					    key[count] = pszKey[R_Ld] ;
					  index[count] = MRD ;

					sectidx[count] = RLmrd ;
					 keyidx[count] = R_Ld ;
					}
				}

				if (SRCH & LLFT) // On left radii
				{
					    ++count ;
					section[count] = pszSection[RLmrd] ;
					    key[count] = pszKey[R_Ll] ;
					  index[count] = LAM ;	  // corresponding index

					sectidx[count] = RLmrd ;
					 keyidx[count] = R_Ll ;

					if (SRCH & MRDS)
					{
						++count ;
					section[count] = pszSection[RLmrd] ;
					    key[count] = pszKey[R_Ll] ;
					  index[count] = MRD ;

					sectidx[count] = RLmrd ;
					 keyidx[count] = R_Ll ;
					}
				}

				if (SRCH & LRYT) // On right radii
				{
					    ++count ;
					section[count] = pszSection[RLmrd] ;
					    key[count] = pszKey[R_Lr] ;
					  index[count] = LAM ;	  // corresponding index

					sectidx[count] = RLmrd ;
					 keyidx[count] = R_Lr ;

					if (SRCH & MRDS)
					{
						++count ;
					section[count] = pszSection[RLmrd] ;
					    key[count] = pszKey[R_Lr] ;
					  index[count] = MRD ;

					sectidx[count] = RLmrd ;
					 keyidx[count] = R_Lr ;
					}
				}
			  }
					if (SRCH & IPDS) // want IPDs
					{
						++count ;
					section[count] = pszSection[Dims] ;
					    key[count] = pszKey[Frmg] ;
					  index[count] = IPD ;

					sectidx[count] = Dims ;
					 keyidx[count] = Frmg ;
					}

			   /******************************************************
					if (SRCH & RSTD) // want Std. Dev. on raw lambdas
					{				 
						++count ;
					section[count] = pszSection[StDv] ;
					    key[count] = pszKey[rStdv] ;
					  index[count] = STD ;
					}

					if (SRCH & MSTD) // want Std. Dev. on mean lambdas
					{				 
						++count ;
					section[count] = pszSection[StDv] ;
					    key[count] = pszKey[mStdv] ;
					  index[count] = STD ;
					}
			   ********************************************************/

	if (WantFile)
	{
			SaveCollFile() ; // Go get the name

		// see if we can create the file
if (hCol = OpenFile(szCollFile, &of, OF_CREATE) == HFILE_ERROR)
          {
		   // Nope. Announce failure.
	        msgbox = 1 ;
			MessageBox(hWndColl,
			          "Can't Create the\nCollation Disk-File.\n\nOperation Cancelled.",
					  "File - Creation Error.",
					   MB_ICONEXCLAMATION|MB_OK) ;
			msgbox = 0 ;
			// Abandon
			WantFile = 0 ;
          }
		else
		{
			// Yep. Shut file.
			_lclose(hCol) ;

			// Re-open it at start for writing.
		hCol = OpenFile(szCollFile, &of, OF_WRITE) ;
		}
	}

// the new Archivist has the dates, and we no longer wish to 
// work only on a daily basis, but by the actual epochs
// of the instances.  We don't need a Workfile.
	
for (k = 0 ; k < iInsts ; k++)
{
	    int ID, iIniID, iInipth ;

			 ID = A.Imgperpfx[CurrentPfxID][k] ;
			fEp = A.fEpperpfx[CurrentPfxID][k] ;

		strcpy(szImageName, DropExt(A.szKnownimg[ID])) ;

		 iIniID = GetIniID(szImageName, 0) ;
		iInipth = sui->iINIpth ;

		strcpy(szIniName, A.szKnownpth[iInipth]) ;
		strcat(szIniName, szImageName) ;
		strcat(szIniName, ".ini") ;

		//		8th April 2005
		// In the new way of working, there are no
		// missing instances, since there is no way
		// to determine whether an instance should
		// or should not be present.  The code for
		// handling missing instances has been removed.

		//***********************************************
		//				Honour requests.
		//***********************************************

					 bud++ ;
			       iYear[bud] =   A.iInstYear[ID] ;
			      iMonth[bud] =  A.iInstMonth[ID] ;
			        iDay[bud] =    A.iInstDay[ID] ;
				   iHour[bud] =   A.iInstHour[ID] ;
				 iMinute[bud] = A.iInstMinute[ID] ;
				 iSecond[bud] = A.iInstSecond[ID] ;


   // Make room, then, if asked, put in
   // bud number, name and date as first fields
   //
   // Roughly match allocation size to the actual number of fields.
   // Assume 20 chars per field and add some for a rainy day.

	if ( szBudItems[bud] != (char *) NULL)
		GlobalFree(szBudItems[bud]) ;

	if (
		(szBudItems[bud] =
		 (char *)GlobalAlloc(GPTR,(count * 20 + 80) * sizeof(char))) == NULL
	   ) // Shit!
		{
		   msgbox = 1 ;
			MessageBox(hWndColl,
				      "BudItem[] Allocations",
				      "Out of Memory",
				       MB_ICONEXCLAMATION|MB_OK) ;
		   msgbox = 0 ;
			return(0) ;
		}

			  if (OrderInSet)
			  {
			  strcpy(szBudItems[bud],_itoa( bud, nbud, 10)) ;
			  strcat(szBudItems[bud],", ") ;
			  }

			  if (DayOfMonth)
			  {
		    // Fill in the bud day of month
			   if (strlen(szBudItems[bud]) == 0)
			     strcpy(szBudItems[bud], _itoa( iDay[bud], nbud, 10)) ;
			     else
	             strcat(szBudItems[bud], _itoa( iDay[bud], nbud, 10)) ;
			  strcat(szBudItems[bud],", ") ;
			  }

			  if (UseBudID)
			  {
			// The image file name, aka prefix and date
			   if (strlen(szBudItems[bud]) == 0)
			     strcpy(szBudItems[bud], szImageName) ;
			     else
			     strcat(szBudItems[bud], szImageName) ;
			  strcat(szBudItems[bud],", ") ;
			  }


			if (count)
			  {
				  for ( item = 1 ; item <= count ; item++ )
				  {
					  gpps(
							 section[item],
					         key[item],
						    "None",
							 buff,
							(DWORD)255,
							 szIniName
						  ) ;
					  
					  // report missing item, and from 
					  // where it should have come
					  if (strcmp(buff,"None") == 0)
					  {
						  char str[256] ;
						  strcpy(str, szIniName) ;
						  strcat(str,"\n\n") ;
						  strcat(str,"[") ;
						  strcat(str, section[item]) ;
						  strcat(str,"],\n\n") ;
						  strcat(str, key[item]) ;
						  strcat(str," value not found.") ;
						  msgbox = 1 ;
						  MessageBox(NULL, str, "Missing Item",
						             MB_ICONEXCLAMATION|MB_OK) ;
						  msgbox = 0 ;
				      }

			// Fill in the fields

			// 13/04/2002:
			// Hrrmmm! We have a problem here,
			// arising from the introduction of
			// field-naming - indices may be wrong.
			// New fields will be named, but old
			// only when the instance is reworked.
			// The inventory does not rework instances.

			// Named,    Lambda is at index 1, MRD is at index 3
			// Nameless, Lambda is at index 0, MRD is at index 1

		    // Let's try something.....

			// If we're wanting a Lambda or an MRD, we're in sections 0 or 1

if (
	sectidx[item] == PLmrd ||
	sectidx[item] == RLmrd
   )
{
				if (index[item] == LAM)                 // Lambda wanted
				{
				  strcpy(string, ParseLine(buff,0)) ;	// check out index zero
				  if (!strcmp(string,"Lambda"))			// is new style
					  strcat(szBudItems[bud],ParseLine(buff,index[item])) ;
				  else									// is old style
					  strcat(szBudItems[bud], string) ;	// Lambda is at index zero
				}

				if (index[item] == MRD)                 // MRD wanted
				{
				  strcpy(string, ParseLine(buff,2)) ;	// check out index 2
				  if (!strcmp(string,"MRD"))			// is new style
					  strcat(szBudItems[bud],ParseLine(buff,index[item])) ;
				  else									// is old style
					  strcat(szBudItems[bud],ParseLine(buff,1) ) ;	// MRD is at index 1
				}
}
else
if (sectidx[item] == Dims) // we want something from the Dimensions section
{
	if (keyidx[item] == Frmg) // under Frame key, we want either IPD, or TLT
	{
				if (index[item] == IPD)                 // IPD wanted
				{
				  strcpy(string, ParseLine(buff,0)) ;	// check out index 0
				  if (
					  !strcmp(string,"IPD:") ||
					  !strcmp(string,"LENGTH:")
					 )		// is new style
					  strcat(szBudItems[bud],ParseLine(buff,index[item])) ;
				  else									// is old style
					  strcat(szBudItems[bud],ParseLine(buff,0) ) ;	// IPD is at index 0
				}

				if (index[item] == TLT)                 // TLT wanted
				{
				  strcpy(string, ParseLine(buff,2)) ;	// first check out index 2
				  if (!strcmp(string,"TILT:"))		    // is named style without units, Tilt is at index 3
				  { strcat(szBudItems[bud],ParseLine(buff,3)) ; goto getout ; }

				  strcpy(string, ParseLine(buff,3)) ;	// now check out index 3
				  if (!strcmp(string,"TILT:"))		    // is named style with units, Tilt is at index 4
				  { strcat(szBudItems[bud],ParseLine(buff,4)) ; goto getout ; }
				  
				  // is old, nameless style
				  strcat(szBudItems[bud],ParseLine(buff,1) ) ;	// Tilt is at index 1
getout: ;
				}
	}
}
else // is none of the above
			strcat(szBudItems[bud], ParseLine(buff,index[item])) ;

				// OK, Seems to have worked. But...what a hack!!
				// Eventually (if all old instances are re-worked)
				// this routine will become redundant.

			// Insert comma delimiter after
			// every item but the last.
			if ( item != count)  
			strcat(szBudItems[bud],", ") ;

				  } // end for (item = ...

			// End line with CR and LF

			   strcat(szBudItems[bud],szCRLF) ;

			   if (WantFile) // write line to file
			    {
			     _hwrite(hCol,szBudItems[bud],strlen(szBudItems[bud])) ;
			    }
			  }
			  else
			  {
				  msgbox = 1 ;
				  MessageBox(hWndColl,
				            "No Items Selected",
							"Null Search",
							 MB_ICONEXCLAMATION|MB_OK) ;
				  msgbox = 0 ;
			  }

		// advance the progress bar
        if (hWndPB1 != NULL) // allow for non-existence of progress bar 
        SendMessage(hWndPB1,
		            PBM_SETPOS,
					(WPARAM)((UINT)(
					10000 * k / iInsts
					)), 0) ;

}
	// Shut the file if any.
	if (WantFile) _lclose(hCol) ;

		// zero the progress bar
        if (hWndPB1 != NULL)
        SendMessage(hWndPB1, PBM_SETPOS, (WPARAM)0, 0) ;
		SetWindowText(hWndFetch,"") ;

	return 1 ;
}

// *********************************************
//  Set up the Control-Button Bitmap rectangles.
// *********************************************
void InitBmControls(void)
{ 
  int i, left, top, right, bottom ;

  for ( i = Opf ; i <= Xit ; i++ )
  {
      left = i * (33 + 2) + 10 ;
       top = 2 ;
     right = left + 33  ;
    bottom = 29;
  
    SetRect(&rctl[i], left, top, right, bottom) ;
  }

    SetRect(&rctl[Prv], 10,          31, 10 + 16, 47) ;		// previous instance button
    SetRect(&rctl[Nxt], 10 + 1 + 16, 31, 27 + 16, 47) ;		//     next instance button
    SetRect(&rctl[Svi], 10 + 2 + 32, 31, 44 + 16, 47) ;		// save all away now button

  for ( i = Lop ; i <= Gry ; i++ )
  {
      left = (i - Lop) * (44 + 2) + 2 ;
       top = 2 ;
     right = left + 44 ;
    bottom = 24 ;

    SetRect(&rctl[i], left, top, right, bottom) ;
  }

  for ( i = Aut ; i <= Prm ; i++ )
  {
      left = (i - Aut) * (44 + 2) + 2 ;
       top = 26 ;
     right = left + 44 ;
    bottom = 48 ;

    SetRect(&rctl[i], left, top, right, bottom) ;
  }

     top = 30 ;
  bottom = top + 20 ;
    left = rctl[Prm].right + 8 ;
   right = left + 44 ;
  SetRect(&rctl[Scc], left, top, right, bottom) ;

  SetRect(    &rcLsa, left, top, right, bottom ) ;
  SetRect(    &rcLsr, left, top, right, bottom ) ;
  SetRect(    &rcLsg, left, top, right, bottom ) ;
  SetRect(    &rcLsb, left, top, right, bottom ) ;

   left = rctl[Prm].right + 8 ;
  right = left + 11 ;
  SetRect(&rctl[Lsa], left, top, right, bottom ) ;

   left = rctl[Prm].right + 8 + 11 ;
  right = left + 11 ;
  SetRect(&rctl[Lsr], left, top, right, bottom ) ;

   left = rctl[Prm].right + 8 + 22 ;
  right = left + 11 ;
  SetRect(&rctl[Lsg], left, top, right, bottom ) ;

   left = rctl[Prm].right + 8 + 33 ;
  right = left + 11 ;
  SetRect(&rctl[Lsb], left, top, right, bottom ) ;

  for ( i = Ca1 ; i <= Ca2 ; i++ )
  {
	  left = (i - Ca1) * (12 + 2) + 2 + rctl[Gry].right;
	   top = 2 ;
	 right = left + 12 ;
	bottom = 24 ;

    SetRect(&rctl[i], left, top, right, bottom) ;
  }

  for ( i = Lum ; i <= Cwh ; i++ )
  {
	    left = (i - Lum) * (70 + 2) + 2 ;
	     top = 2 ;
	   right = left + 70 ;
	  bottom = top + 16 ;
    SetRect(&rctl[i], left, top, right, bottom) ;
  }

  for ( i = Prj ; i <= Dtl ; i++ )
  {
	  left = (i - Prj) * (48 + 2) + 2 ;
	   top = 2;
	 right = left + 48;
	bottom = top + 18 ;
    SetRect(&rctl[i], left, top, right, bottom) ;
  }


 for ( i = Oex ; i <= Pmx ; i++ )
 {
	 left = (i - Oex) * (28 + 4) + 32 ;
	  top = 2 ;
	right = left + 28 ;
   bottom =  top + 28 ;
   SetRect( &rctl[i], left, top, right, bottom) ;
 }

 for ( i = Rot ; i <= Tst ; i++ )
 {
	 left = 2 ;
	  top = (i - Rot) * (28 + 4) + 32 ;
	right = left + 28 ;
   bottom =  top + 28 ;
   SetRect( &rctl[i], left, top, right, bottom) ;
 }

 for ( i = Itm ; i <= Fou ; i++ )
 {
	   left = (i - Itm) * (44 + 2) + 2 ;
	    top = 0 ; 
	  right = left + 44 ;
	 bottom =  top + 31 ;
	 SetRect( &rctl[i], left, top, right, bottom) ;
 }
 
 SetRect( &rctl[Fos], 2, 2, 32, 17) ;

 SetRect(&rctl[Rez],
	     2,
		 rcb.bottom - 17,
		 40,
		 rcb.bottom - 1) ;
}
