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

#define MAX_ITEMS 11

static XPLMDataRef gPositionDataRef[MAX_ITEMS];

static char DataRefString[MAX_ITEMS][255] = {	"sim/flightmodel/position/local_x", "sim/flightmodel/position/local_y", "sim/flightmodel/position/local_z",
										"sim/flightmodel/position/lat_ref", "sim/flightmodel/position/lon_ref",	"sim/flightmodel/position/theta",
										"sim/flightmodel/position/phi", "sim/flightmodel/position/psi",
										"sim/flightmodel/position/latitude", "sim/flightmodel/position/longitude", "sim/flightmodel/position/elevation"};

static char DataRefDesc[MAX_ITEMS][255] = {"Local x", "Local y", "Local z", "Lat Ref", "Lon Ref", "Theta", "Phi", "Psi"};
static char Description[3][255] = {"Latitude", "Longitude", "Elevation"};

static int	Element = 0, IntVals[128];
static float FloatVals[128];
static int ByteVals[128];

static int MenuItem1;

static XPWidgetID			PositionWidget = NULL, PositionWindow = NULL;
static XPWidgetID			PositionApplyButton = NULL;
static XPWidgetID			PositionText[MAX_ITEMS] = {NULL};
static XPWidgetID			PositionEdit[MAX_ITEMS] = {NULL};
static XPWidgetID			UpArrow[MAX_ITEMS] = {NULL};
static XPWidgetID			DownArrow[MAX_ITEMS] = {NULL};
static XPWidgetID			LatLonAltApplyButton = NULL, LatLonRefApplyButton = NULL, ReloadSceneryButton = NULL;
static XPWidgetID			Position2Text[3] = {NULL};
static XPWidgetID			Position2Edit[3] = {NULL};

static void PositionMenuHandler(void *, void *);

static void CreatePosition(int x1, int y1, int w, int h);

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

static void DisplayFindDataRef(void);
static void ApplyValues(void);
static void ApplyLatLonRefValues(void);
static void ApplyLatLonAltValues(void);

inline	float	HACKFLOAT(float val)
{
	return val;
}
/*
#if IBM
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
*/

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

	strcpy(outName, "Position");
	strcpy(outSig, "xpsdk.examples.position");
	strcpy(outDesc, "A plug-in that allows positioning of lat/lon etc.");

	item = XPLMAppendMenuItem(XPLMFindPluginsMenu(), "Position", NULL, 1);

	id = XPLMCreateMenu("Position", XPLMFindPluginsMenu(), item, PositionMenuHandler, NULL);
	XPLMAppendMenuItem(id, "Position", (void *)"Position", 1);

	MenuItem1 = 0;

	for (int Item=0; Item<MAX_ITEMS; Item++)
		gPositionDataRef[Item] = XPLMFindDataRef(DataRefString[Item]);

	return 1;
}

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

PLUGIN_API void XPluginDisable(void)
{
}

PLUGIN_API int XPluginEnable(void)
{
	return 1;
}

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

void PositionMenuHandler(void * mRef, void * iRef)
{
	if (!strcmp((char *) iRef, "Position"))
	{
		if (MenuItem1 == 0)
		{
			CreatePosition(300, 600, 300, 550);
			MenuItem1 = 1;
		}
		else
			if(!XPIsWidgetVisible(PositionWidget))
				XPShowWidget(PositionWidget);
	}
}


void CreatePosition(int x, int y, int w, int h)
{
	int x2 = x + w;
	int y2 = y - h;
	float FloatValue[MAX_ITEMS];
	double DoubleValue[3];

	char buffer[512];
	int Item;

	for (Item=0; Item<MAX_ITEMS; Item++)
		FloatValue[Item] = XPLMGetDataf(gPositionDataRef[Item]);

	/// X, Y, Z, Lat, Lon, Alt
	XPLMLocalToWorld(FloatValue[0], FloatValue[1], FloatValue[2], &DoubleValue[0], &DoubleValue[1], &DoubleValue[2]);
	DoubleValue[2] *= 3.28;

	PositionWidget = XPCreateWidget(x, y, x2, y2,
					1,	// Visible
					"Position",	// desc
					1,		// root
					NULL,	// no container
					xpWidgetClass_MainWindow);

	XPSetWidgetProperty(PositionWidget, xpProperty_MainWindowHasCloseBoxes, 1);

	PositionWindow = XPCreateWidget(x+50, y-50, x2-50, y2+50,
					1,	// Visible
					"",	// desc
					0,		// root
					PositionWidget,
					xpWidgetClass_SubWindow);

	XPSetWidgetProperty(PositionWindow, xpProperty_SubWindowType, xpSubWindowStyle_SubWindow);

	for (Item=0; Item<MAX_ITEMS-3; Item++)
	{
		PositionText[Item] = XPCreateWidget(x+60, y-(70 + (Item*30)), x+115, y-(92 + (Item*30)),
							1,	// Visible
							DataRefDesc[Item],// desc
							0,		// root
							PositionWidget,
							xpWidgetClass_Caption);

		sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
		PositionEdit[Item] = XPCreateWidget(x+120, y-(70 + (Item*30)), x+210, y-(92 + (Item*30)),
							1, buffer, 0, PositionWidget,
							xpWidgetClass_TextField);

		XPSetWidgetProperty(PositionEdit[Item], xpProperty_TextFieldType, xpTextEntryField);

		UpArrow[Item] = XPCreateWidget(x+212, y-(66 + (Item*30)), x+224, y-(81 + (Item*30)),
							1, "", 0, PositionWidget,
							xpWidgetClass_Button);

		XPSetWidgetProperty(UpArrow[Item], xpProperty_ButtonType, xpLittleUpArrow);

		DownArrow[Item] = XPCreateWidget(x+212, y-(81 + (Item*30)), x+224, y-(96 + (Item*30)),
							1, "", 0, PositionWidget,
							xpWidgetClass_Button);

		XPSetWidgetProperty(DownArrow[Item], xpProperty_ButtonType, xpLittleDownArrow);
	}

	PositionApplyButton = XPCreateWidget(x+50, y-310, x+140, y-332,
					1, "Apply Data", 0, PositionWidget,
					xpWidgetClass_Button);

	XPSetWidgetProperty(PositionApplyButton, xpProperty_ButtonType, xpPushButton);


	LatLonRefApplyButton = XPCreateWidget(x+145, y-310, x+240, y-332,
					1, "Apply LatLonRef", 0, PositionWidget, 
					xpWidgetClass_Button);

	XPSetWidgetProperty(LatLonRefApplyButton, xpProperty_ButtonType, xpPushButton);


	for (Item=0; Item<3; Item++)
	{
		Position2Text[Item] = XPCreateWidget(x+60, y-(350 + (Item*30)), x+115, y-(372 + (Item*30)),
							1,	// Visible
							Description[Item],// desc
							0,		// root
							PositionWidget,
							xpWidgetClass_Caption);
	
		sprintf(buffer, "%lf", HACKFLOAT(DoubleValue[Item]));
		Position2Edit[Item] = XPCreateWidget(x+120, y-(350 + (Item*30)), x+210, y-(372 + (Item*30)),
							1, buffer, 0, PositionWidget,
							xpWidgetClass_TextField);

		XPSetWidgetProperty(PositionEdit[Item], xpProperty_TextFieldType, xpTextEntryField);
	}
	
	LatLonAltApplyButton = XPCreateWidget(x+70, y-440, x+220, y-462,
						1, "Apply LatLonAlt", 0, PositionWidget, 
						xpWidgetClass_Button);

	XPSetWidgetProperty(LatLonAltApplyButton, xpProperty_ButtonType, xpPushButton);

	ReloadSceneryButton = XPCreateWidget(x+70, y-465, x+220, y-487,
						1, "Reload Scenery", 0, PositionWidget, 
						xpWidgetClass_Button);

	XPSetWidgetProperty(ReloadSceneryButton, xpProperty_ButtonType, xpPushButton);

	XPAddWidgetCallback(PositionWidget, PositionHandler);
}

int	PositionHandler(
						XPWidgetMessage			inMessage,
						XPWidgetID				inWidget,
						intptr_t				inParam1,
						intptr_t				inParam2)
{
	float FloatValue[MAX_ITEMS];
	char buffer[512];
	int Item;

	for (Item=0; Item<MAX_ITEMS; Item++)
		FloatValue[Item] = XPLMGetDataf(gPositionDataRef[Item]);

	if (inMessage == xpMessage_CloseButtonPushed)
		{
			if (MenuItem1 == 1)
			{
				XPHideWidget(PositionWidget);
			}
			return 1;
		}

	if (inMessage == xpMsg_PushButtonPressed)
	{
		if (inParam1 == (intptr_t)PositionApplyButton)
		{
			ApplyValues();
			return 1;
		}

		if (inParam1 == (intptr_t)LatLonRefApplyButton)
		{
			ApplyLatLonRefValues();
			return 1;
		}

		if (inParam1 == (intptr_t)LatLonAltApplyButton)
		{
			ApplyLatLonAltValues();
			return 1;
		}

		if (inParam1 == (intptr_t)ReloadSceneryButton)
		{
			XPLMReloadScenery();
			return 1;
		}

		for (Item=0; Item<MAX_ITEMS-3; Item++)
		{
			if (inParam1 == (intptr_t)UpArrow[Item])
			{
				FloatValue[Item] += 1.0;
				sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
				XPSetWidgetDescriptor(PositionEdit[Item], buffer);
				XPLMSetDataf(gPositionDataRef[Item], FloatValue[Item]);
				return 1;
			}
		}

		for (Item=0; Item<MAX_ITEMS-3; Item++)
		{
			if (inParam1 == (intptr_t)DownArrow[Item])
			{
				FloatValue[Item] -= 1.0;
				sprintf(buffer, "%f", HACKFLOAT(FloatValue[Item]));
				XPSetWidgetDescriptor(PositionEdit[Item], buffer);
				XPLMSetDataf(gPositionDataRef[Item], FloatValue[Item]);
				return 1;
			}
		}
	}
	return 0;
}						

void ApplyValues(void)
{
	char	buffer[512];

	for (int Item=0; Item<MAX_ITEMS-3; Item++)
	{
		XPGetWidgetDescriptor(PositionEdit[Item], buffer, 512);
		XPLMSetDataf(gPositionDataRef[Item], atof(buffer));
	}
}

void ApplyLatLonRefValues(void)
{
	float FloatValue;
	char	buffer[512];

	XPGetWidgetDescriptor(PositionEdit[3], buffer, 512);
	FloatValue = atof(buffer);
	XPLMSetDataf(gPositionDataRef[3], FloatValue);

	XPGetWidgetDescriptor(PositionEdit[4], buffer, 512);
	FloatValue = atof(buffer);
	XPLMSetDataf(gPositionDataRef[4], FloatValue);
}

void ApplyLatLonAltValues(void)
{
	float FloatValue[3];
	double DoubleValue[3];
	char	buffer[512];
	int Item;

	// This gets the lat/lon/alt from the widget text fields
	for (Item=0; Item<3; Item++)
	{
		XPGetWidgetDescriptor(Position2Edit[Item], buffer, 512);
		FloatValue[Item] = atof(buffer);
	}

	/// Lat, Lon, Alt, X, Y, Z
	XPLMWorldToLocal(FloatValue[0], FloatValue[1], FloatValue[2] / 3.28, &DoubleValue[0], &DoubleValue[1], &DoubleValue[2]);  

	for (Item=0; Item<3; Item++)
	{
		// This writes out the lat/lon/alt from the widget text fields back to the datarefs
		XPLMSetDataf(gPositionDataRef[Item+8], FloatValue[Item]);
		// This writes out the x,y,z datarefs after conversion from lat/lon/alt back to the datarefs
		XPLMSetDataf(gPositionDataRef[Item], DoubleValue[Item]);
	}

	ApplyLatLonRefValues();
}

4 comments on “Position

  1. Hi, I have copied this plugin to visual studio 2017 and after adding libraries and other paths I tried to compile it. Here is a message:

    ‘void XPAddWidgetCallback(XPWidgetID,XPWidgetFunc_t)’: cannot convert argument 2 from ‘int (__cdecl*)(XPWidgetMessage,XPWidgetID,intptr_t,intptr_t)’ to ‘XPWidgetFunc_t’

    I have no idea what to do and how to solve this issue.

    1. Just so others know, in order to fix this error for X-Plane 11 64-bit, all you need to do is to replace the SDK subfolder in this example package with the official SDK v3, which is 64 bit compatible. The problem is to do with the fact that the sample was updated for the 64-bit, but the included SDK was not.

  2. This may be untimely since it has been a few months since the original question…

    But I was able to compile in Visual Studio 2017 by correcting the error line (line # 254 in positon.cpp)
    as follows:
    XPAddWidgetCallback(PositionWidget, (XPWidgetFunc_t) PositionHandler);

    I also had to add the library path from the SDK (e.g. C:…\X-Plane SDK\SDK\Libraries\Win) to the project properties to get it to link.

  3. I tried to post a reply to this once already, hopefully this doesn’t end up as a duplicate but I don’t see my reply so I will try once more….
    It may be a little late since its been a couple of months since the question was posted – but I was able to successfully compile this example in Visual Studio 2017 by changing the error line (line 264 in position.cpp) as follows:

    XPAddWidgetCallback(PositionWidget, (XPWidgetFunc_t) PositionHandler);

    I also had to add a path to the SDK libraries in order to get the project to link (i.e. to complete the build)
    e.g. C:…..\SDK\Libraries\Win\XPLM_64.lib
    (See project properties menu, linker category, general sub-category, additional directories entry.)

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.