/*
	FMSUtility Example
	Written by Sandy Barbour - 21/01/2005
	
	This examples shows how to access the FMS
*/

#include "XPLMPlugin.h"
#include "XPLMUtilities.h"
#include "XPLMProcessing.h"
#include "XPLMMenus.h"
#include "XPLMGraphics.h"
#include "XPLMPlanes.h"
#include "XPLMDataAccess.h"
#include "XPLMNavigation.h"
#include "XPWidgets.h"
#include "XPStandardWidgets.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#if IBM
#include <windows.h>
#endif


#define MAX_NAV_TYPES 13
#define MAX_FMS_ENTRIES 100

static int MenuItem1, NavTypeLinePosition;

/// Widgets
static XPWidgetID FMSUtilityWidget = NULL, FMSUtilityWindow1 = NULL, FMSUtilityWindow2 = NULL;
static XPWidgetID GetFMSEntryButton, ClearEntryButton;
static XPWidgetID GetEntryIndexButton, SetEntryIndexButton, GetDestinationEntryButton, SetDestinationEntryButton;
static XPWidgetID EntryIndexEdit, DestinationEntryIndexEdit;
static XPWidgetID GetNumberOfEntriesButton, GetNumberOfEntriesText;
static XPWidgetID IndexCaption, IndexEdit, SegmentCaption, SegmentCaption2, AirportIDCaption, AirportIDEdit, AltitudeCaption, AltitudeEdit;
static XPWidgetID NavTypeCaption, NavTypeEdit, NavTypeText, UpArrow, DownArrow, SetFMSEntryButton;
static XPWidgetID LatCaption, LatEdit, LonCaption, LonEdit, SetLatLonButton;


/// Structure for the nav types and a more meaningful description
typedef struct _NAVTYPE
{
    char Description[80];
    XPLMNavType EnumValue;
} NAVTYPE;

static NAVTYPE NavTypeLookup[MAX_NAV_TYPES] = {{"Unknown",			xplm_Nav_Unknown},
                                        {"Airport",			xplm_Nav_Airport},
                                        {"NDB",				xplm_Nav_NDB},
                                        {"VOR",				xplm_Nav_VOR},
                                        {"ILS",				xplm_Nav_ILS},
                                        {"Localizer",		xplm_Nav_Localizer},
                                        {"Glide Slope",		xplm_Nav_GlideSlope},
                                        {"Outer Marker",	xplm_Nav_OuterMarker},
                                        {"Middle Marker",	xplm_Nav_MiddleMarker},
                                        {"Inner Marker",	xplm_Nav_InnerMarker},
                                        {"Fix",				xplm_Nav_Fix},
                                        {"DME",				xplm_Nav_DME},
                                        {"Lat/Lon",			xplm_Nav_LatLon}};

/// Utility functions and callbacks

/// This is used to get around a sprintf float bug with codewarrior on the mac
inline	float	HACKFLOAT(float val)
{
	return val;
}
/*
#if IBM || LIN
inline	float	HACKFLOAT(float val)
{
	return val;
}
#else
inline long long HACKFLOAT(float val)
{
	double	d = val;
	long long temp;
	temp = *((long long *) &d);
	return temp;
}
#endif
*/

static void FMSUtilityMenuHandler(void *, void *);
static void CreateFMSUtilityWidget(int x1, int y1, int w, int h);
static int GetCBIndex(int Type);

static int FMSUtilityHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						intptr_t				inParam1,
						intptr_t				inParam2);


PLUGIN_API int XPluginStart(
						char *		outName,
						char *		outSig,
						char *		outDesc)
{
	XPLMMenuID	id;
	int			item;

	strcpy(outName, "FMS Utility");
	strcpy(outSig, "xpsdk.experimental.FMSUtility");
	strcpy(outDesc, "A plug-in that accesses the FMS.");

	// Create our menu
	item = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "FMSUtility", NULL, 1);
	id = XPLMCreateMenu("FMSUtility", XPLMFindPluginsMenu(), item, FMSUtilityMenuHandler, NULL);
	XPLMAppendMenuItem(id, "Utility Panel", (void *)"FMSUtility", 1);

	// Flag to tell us if the widget is being displayed.
	MenuItem1 = 0;
	NavTypeLinePosition = 0;

	return 1;
}

PLUGIN_API void	XPluginStop(void)
{
	if (MenuItem1 == 1)
	{
		XPDestroyWidget(FMSUtilityWidget, 1);
		MenuItem1 = 0;
	}
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API void XPluginReceiveMessage(XPLMPluginID inFrom, int inMsg, void * inParam)
{
}


// This will create our widget from menu selection.
// MenuItem1 flag stops it from being created more than once.
void FMSUtilityMenuHandler(void * mRef, void * iRef)
{
	// If menu selected create our widget dialog
	if (!strcmp((char *) iRef, "FMSUtility"))
	{
		if (MenuItem1 == 0)
		{
			CreateFMSUtilityWidget(221, 640, 420, 290);
			MenuItem1 = 1;
		}
		else
			if(!XPIsWidgetVisible(FMSUtilityWidget))
				XPShowWidget(FMSUtilityWidget);
	}
}						


// This will create our widget dialog.
// I have made all child widgets relative to the input paramter.
// This makes it easy to position the dialog
void CreateFMSUtilityWidget(int x, int y, int w, int h)
{
	int x2 = x + w;
	int y2 = y - h;
	char Buffer[255];
	

	strcpy(Buffer, "FMS Example by Sandy Barbour - 2005");

	// Create the Main Widget window
	FMSUtilityWidget = XPCreateWidget(x, y, x2, y2,
					1,	// Visible
					Buffer,	// desc
					1,		// root
					NULL,	// no container
					xpWidgetClass_MainWindow);

	// Add Close Box decorations to the Main Widget
	XPSetWidgetProperty(FMSUtilityWidget, xpProperty_MainWindowHasCloseBoxes, 1);

	// Create the Sub Widget1 window
	FMSUtilityWindow1 = XPCreateWidget(x+10, y-30, x+160, y2+10,
					1,	// Visible
					"",	// desc
					0,		// root
					FMSUtilityWidget,
					xpWidgetClass_SubWindow);

	// Set the style to sub window
	XPSetWidgetProperty(FMSUtilityWindow1, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

	// Create the Sub Widget2 window
	FMSUtilityWindow2 = XPCreateWidget(x+170, y-30, x2-10, y2+10,
					1,	// Visible
					"",	// desc
					0,		// root
					FMSUtilityWidget,
					xpWidgetClass_SubWindow);

	// Set the style to sub window
	XPSetWidgetProperty(FMSUtilityWindow2, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

	/// Entry Index
	GetEntryIndexButton = XPCreateWidget(x+20, y-40, x+110, y-62,
					1, " Get Entry Index", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(GetEntryIndexButton, xpProperty_ButtonType, xpPushButton);

	EntryIndexEdit = XPCreateWidget(x+120, y-40, x+150, y-62,
					1, "0", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(EntryIndexEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(EntryIndexEdit, xpProperty_Enabled, 1);

	SetEntryIndexButton = XPCreateWidget(x+20, y-70, x+110, y-92,
					1, " Set Entry Index", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(SetEntryIndexButton, xpProperty_ButtonType, xpPushButton);

	/// Destination Index
	GetDestinationEntryButton = XPCreateWidget(x+20, y-100, x+110, y-122,
					1, " Get Dest Index", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(GetDestinationEntryButton, xpProperty_ButtonType, xpPushButton);

	DestinationEntryIndexEdit = XPCreateWidget(x+120, y-100, x+150, y-122,
					1, "0", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(DestinationEntryIndexEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(DestinationEntryIndexEdit, xpProperty_Enabled, 1);

	SetDestinationEntryButton = XPCreateWidget(x+20, y-130, x+110, y-152,
					1, " Set Dest Index", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(SetDestinationEntryButton, xpProperty_ButtonType, xpPushButton);

	/// Number of Entries
	GetNumberOfEntriesButton = XPCreateWidget(x+20, y-160, x+110, y-182,
					1, " Get No. Entries", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(GetNumberOfEntriesButton, xpProperty_ButtonType, xpPushButton);

	GetNumberOfEntriesText = XPCreateWidget(x+120, y-160, x+150, y-182,
					1, "", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(GetNumberOfEntriesText, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(GetNumberOfEntriesText, xpProperty_Enabled, 0);

	/// Clear Entry
	ClearEntryButton = XPCreateWidget(x+20, y-190, x+110, y-212,
					1, " Clear Entry", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(ClearEntryButton, xpProperty_ButtonType, xpPushButton);

	/// Index (Segment - 1)
	IndexCaption = XPCreateWidget(x+180, y-40, x+230, y-62,
					1, "Index", 0, FMSUtilityWidget,
					xpWidgetClass_Caption);

	IndexEdit = XPCreateWidget(x+240, y-40, x+290, y-62,
					1, "0", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(IndexEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(IndexEdit, xpProperty_Enabled, 1);

	SegmentCaption = XPCreateWidget(x+300, y-40, x+350, y-62,
					1, "Segment", 0, FMSUtilityWidget,
					xpWidgetClass_Caption);
					
	SegmentCaption2 = XPCreateWidget(x+360, y-40, x+410, y-62,
					1, "1", 0, FMSUtilityWidget,
					xpWidgetClass_Caption);
					
	/// Airport ID
	AirportIDCaption = XPCreateWidget(x+180, y-70, x+230, y-92,
					1, "Airport ID", 0, FMSUtilityWidget,
					xpWidgetClass_Caption);

	AirportIDEdit = XPCreateWidget(x+240, y-70, x+290, y-92,
					1, "----", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(AirportIDEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(AirportIDEdit, xpProperty_Enabled, 1);

	/// Altitude
	AltitudeCaption = XPCreateWidget(x+180, y-100, x+230, y-122,
					1, "Altitude", 0, FMSUtilityWidget,
					xpWidgetClass_Caption);

	AltitudeEdit = XPCreateWidget(x+240, y-100, x+290, y-122,
					1, "0", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(AltitudeEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(AltitudeEdit, xpProperty_Enabled, 1);

	/// Nav Type
	NavTypeCaption = XPCreateWidget(x+180, y-130, x+230, y-152,
					1, "Nav Type", 0, FMSUtilityWidget,
					xpWidgetClass_Caption);

	sprintf(Buffer, "%s", NavTypeLookup[0].Description);
	NavTypeEdit = XPCreateWidget(x+240, y-130, x+340, y-152,
					1, Buffer, 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(NavTypeEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(NavTypeEdit, xpProperty_Enabled, 0);

	// Used for selecting Nav Type
	UpArrow = XPCreateWidget(x+340, y-130, x+362, y-141,
							1, "", 0, FMSUtilityWidget,
							xpWidgetClass_Button);

	XPSetWidgetProperty(UpArrow, xpProperty_ButtonType, xpLittleUpArrow);

	// Used for selecting Nav Type
	DownArrow = XPCreateWidget(x+340, y-141, x+362, y-152,
							1, "", 0, FMSUtilityWidget,
							xpWidgetClass_Button);
	
	XPSetWidgetProperty(DownArrow, xpProperty_ButtonType, xpLittleDownArrow);

	NavTypeText = XPCreateWidget(x+362, y-130, x+400, y-152,
					1, "0", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(NavTypeText, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(NavTypeText, xpProperty_Enabled, 0);

	/// Get FMS Entry Info
	GetFMSEntryButton = XPCreateWidget(x+180, y-160, x+270, y-182,
					1, " Get FMS Entry", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(GetFMSEntryButton, xpProperty_ButtonType, xpPushButton);

	/// Set FMS Entry Info
	SetFMSEntryButton = XPCreateWidget(x+280, y-160, x+370, y-182,
					1, " Set FMS Entry", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(SetFMSEntryButton, xpProperty_ButtonType, xpPushButton);

	/// Lat / Lon
	LatCaption = XPCreateWidget(x+180, y-190, x+230, y-212,
					1, "Latitude", 0, FMSUtilityWidget,
					xpWidgetClass_Caption);

	LatEdit = XPCreateWidget(x+240, y-190, x+310, y-212,
					1, "0", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(LatEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(LatEdit, xpProperty_Enabled, 1);

	LonCaption = XPCreateWidget(x+180, y-220, x+230, y-242,
					1, "Longitude", 0, FMSUtilityWidget,
					xpWidgetClass_Caption);

	LonEdit = XPCreateWidget(x+240, y-220, x+310, y-242,
					1, "0", 0, FMSUtilityWidget,
					xpWidgetClass_TextField);

	XPSetWidgetProperty(LonEdit, xpProperty_TextFieldType, xpTextEntryField);
	XPSetWidgetProperty(LonEdit, xpProperty_Enabled, 1);

	SetLatLonButton = XPCreateWidget(x+180, y-250, x+270, y-272,
					1, " Set Lat/Lon", 0, FMSUtilityWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(SetLatLonButton, xpProperty_ButtonType, xpPushButton);

	// Register our widget handler
	XPAddWidgetCallback(FMSUtilityWidget, FMSUtilityHandler);
}

// This is the handler for our widget
// It can be used to process button presses etc.
// In this example we are only interested when the close box is pressed
int	FMSUtilityHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						intptr_t				inParam1,
						intptr_t				inParam2)
{
	void *Param;    
	Param = 0;    
	char Buffer[255];

	// Close button will get rid of our main widget
	// All child widgets will get the bullet as well
	if (inMessage == xpMessage_CloseButtonPushed)
	{
		if (MenuItem1 == 1)
		{
			XPHideWidget(FMSUtilityWidget);
		}
		return 1;
	}

	// Handle any button pushes
	if (inMessage == xpMsg_PushButtonPressed)
	{
		/// Most of these handlers get a value.
		/// It then has to be converted to a string using sprintf.
		/// This is because "XPSetWidgetDescriptor" expects a string as its second parameter.
		if (inParam1 == (intptr_t)ClearEntryButton)
		{
		    XPLMClearFMSEntry(XPLMGetDisplayedFMSEntry());
			return 1;
		}
		
		if (inParam1 == (intptr_t)GetEntryIndexButton)
		{
		    int Index = XPLMGetDisplayedFMSEntry();
			sprintf(Buffer, "%d", Index);
			XPSetWidgetDescriptor(EntryIndexEdit, Buffer);
			return 1;
		}
		
		if (inParam1 == (intptr_t)SetEntryIndexButton)
		{
			XPGetWidgetDescriptor(EntryIndexEdit, Buffer, sizeof(Buffer));
		    int Index = atoi(Buffer);
			XPLMSetDisplayedFMSEntry(Index);
			return 1;
		}
		
		if (inParam1 == (intptr_t)GetDestinationEntryButton)
		{
		    int Index = XPLMGetDestinationFMSEntry();
			sprintf(Buffer, "%d", Index);
			XPSetWidgetDescriptor(DestinationEntryIndexEdit, Buffer);
			return 1;
		}
		
		if (inParam1 == (intptr_t)SetDestinationEntryButton)
		{
			XPGetWidgetDescriptor(DestinationEntryIndexEdit, Buffer, sizeof(Buffer));
		    int Index = atoi(Buffer);
			XPLMSetDestinationFMSEntry(Index);
			return 1;
		}
		
		if (inParam1 == (intptr_t)GetNumberOfEntriesButton)
		{
		    int Count = XPLMCountFMSEntries();
			sprintf(Buffer, "%d", Count);
			XPSetWidgetDescriptor(GetNumberOfEntriesText, Buffer);
			return 1;
		}
		
		if (inParam1 == (intptr_t)GetFMSEntryButton)
		{
			int Index = XPLMGetDisplayedFMSEntry();
		    XPLMNavType outType;
			char outID[80];
			XPLMNavRef outRef;
			int outAltitude;
			float outLat;
			float outLon;
	
			XPLMGetFMSEntryInfo(Index, &outType, outID, &outRef, &outAltitude, &outLat, &outLon);
			sprintf(Buffer, "%d", Index);
			XPSetWidgetDescriptor(IndexEdit, Buffer);
			sprintf(Buffer, "%d", Index+1);
			XPSetWidgetDescriptor(SegmentCaption2, Buffer);
			if (outType == xplm_Nav_LatLon)
				XPSetWidgetDescriptor(AirportIDEdit, "----");
			else
				XPSetWidgetDescriptor(AirportIDEdit, outID);
			sprintf(Buffer, "%d", outAltitude);
			XPSetWidgetDescriptor(AltitudeEdit, Buffer);
			XPSetWidgetDescriptor(NavTypeEdit, NavTypeLookup[GetCBIndex(outType)].Description);
			sprintf(Buffer, "%d", NavTypeLookup[GetCBIndex(outType)].EnumValue);
			XPSetWidgetDescriptor(NavTypeText, Buffer);
			sprintf(Buffer, "%+05.2f", HACKFLOAT(outLat));
			XPSetWidgetDescriptor(LatEdit, Buffer);
			sprintf(Buffer, "%+05.2f", HACKFLOAT(outLon));
			XPSetWidgetDescriptor(LonEdit, Buffer);

			return 1;
		}
		
		if (inParam1 == (intptr_t)SetFMSEntryButton)
		{
			XPGetWidgetDescriptor(IndexEdit, Buffer, sizeof(Buffer));
			int Index = atoi(Buffer);
			sprintf(Buffer, "%d", Index+1);
			XPSetWidgetDescriptor(SegmentCaption2, Buffer);
			XPGetWidgetDescriptor(AltitudeEdit, Buffer, sizeof(Buffer));
			int Altitude = atoi(Buffer);
			XPGetWidgetDescriptor(NavTypeText, Buffer, sizeof(Buffer));
			int NavType = atoi(Buffer);
			XPGetWidgetDescriptor(AirportIDEdit, Buffer, sizeof(Buffer));
			XPLMSetFMSEntryInfo(Index, XPLMFindNavAid(NULL, Buffer, NULL, NULL, NULL, NavType), Altitude);

			return 1;
		}
		
		if (inParam1 == (intptr_t)SetLatLonButton)
		{
			XPGetWidgetDescriptor(IndexEdit, Buffer, sizeof(Buffer));
			int Index = atoi(Buffer);
			sprintf(Buffer, "%d", Index+1);
			XPSetWidgetDescriptor(SegmentCaption2, Buffer);
			XPGetWidgetDescriptor(AltitudeEdit, Buffer, sizeof(Buffer));
			int Altitude = atoi(Buffer);
			XPGetWidgetDescriptor(LatEdit, Buffer, sizeof(Buffer));
			float Lat = atof(Buffer);
			XPGetWidgetDescriptor(LonEdit, Buffer, sizeof(Buffer));
			float Lon = atof(Buffer);
			XPLMSetFMSEntryLatLon(Index, Lat, Lon, Altitude);

			return 1;
		}
		
		// Up Arrow is used to modify the NavTypeLookup Array Index 
		if (inParam1 == (intptr_t)UpArrow)
		{
			NavTypeLinePosition--;
			if (NavTypeLinePosition < 0)
				NavTypeLinePosition = MAX_NAV_TYPES-1;
			XPSetWidgetDescriptor(NavTypeEdit, NavTypeLookup[NavTypeLinePosition].Description);
			sprintf(Buffer, "%d", NavTypeLookup[NavTypeLinePosition].EnumValue);
			XPSetWidgetDescriptor(NavTypeText, Buffer);

			return 1;
		}

		// Down Arrow is used to modify the NavTypeLookup Array Index 
		if (inParam1 == (intptr_t)DownArrow)
		{
			NavTypeLinePosition++;
			if (NavTypeLinePosition > MAX_NAV_TYPES-1)
				NavTypeLinePosition = 0;
			XPSetWidgetDescriptor(NavTypeEdit, NavTypeLookup[NavTypeLinePosition].Description);
			sprintf(Buffer, "%d", NavTypeLookup[NavTypeLinePosition].EnumValue);
			XPSetWidgetDescriptor(NavTypeText, Buffer);

			return 1;
		}

	}

	return 0;
}						

/// This function takes an XPLMNavType and
/// returns the index into the NavTypeLookup array.
/// We can then use that index to access the description or enum.
int GetCBIndex(int Type)
{
    int CBIndex = 0;

    for (int Index=0; Index<MAX_NAV_TYPES; Index++)
    {
        if (NavTypeLookup[Index].EnumValue == Type)
        {
            CBIndex = Index;
            break;
        }
    }
    return CBIndex;
}

Leave a Reply

Your email address will not be published. Required fields are marked *

Please do not report bugs in the blog comments.
Only bugs reported via the X-Plane Bug Reporter are tracked.