From c184a3de7f62d6dd841918359dca381de44b7368 Mon Sep 17 00:00:00 2001 From: GioCC Date: Fri, 14 Apr 2023 12:20:35 +0200 Subject: [PATCH 01/13] MOD: inbound argument parsing refactored [TO BE TESTED] Avoid code duplication by introducing _seekParm() aux function --- XPLPro_Arduino/XPLPro.cpp | 128 ++++++++++++++------------------------ XPLPro_Arduino/XPLPro.h | 1 + 2 files changed, 47 insertions(+), 82 deletions(-) diff --git a/XPLPro_Arduino/XPLPro.cpp b/XPLPro_Arduino/XPLPro.cpp index 4cdea8d..cce9bff 100644 --- a/XPLPro_Arduino/XPLPro.cpp +++ b/XPLPro_Arduino/XPLPro.cpp @@ -332,36 +332,43 @@ void XPLPro::_transmitPacket(void) } } -int XPLPro::_parseString(char *outBuffer, char *inBuffer, int parameter, int maxSize)// todo: Confirm 0 length strings ("") dont cause issues +void XPLPro::_seekParm(const char* buf, int paramIdx, int& start, int &end) { + int pos = 0; + // search for the selected parameter + for (int i = 1; i < paramIdx; i++) { + while (buf[pos] != ',' && buf[pos] != 0) pos++; + if(buf[pos] != 0)pos++; // skip separator + } + // parameter starts here + start = pos; + // search for end of parameter + while (buf[pos] != ',' && buf[pos] != 0 && buf[pos] != XPL_PACKETTRAILER) pos++; + end = pos; +} + + +int XPLPro::_parseString(char *outBuffer, char *inBuffer, int parameter, int maxSize) +{ + // todo: Confirm 0 length strings ("") dont cause issues int cBeg; int pos = 0; int len; - for (int i = 1; i < parameter; i++) - { - while (inBuffer[pos] != ',' && inBuffer[pos] != 0) - { - pos++; - } - pos++; + for (int i = 1; i < parameter; i++) { + while (inBuffer[pos] != ',' && inBuffer[pos] != 0) pos++; + if(inBuffer[pos] != 0) pos++; } - while (inBuffer[pos] != '\"' && inBuffer[pos] != 0) - { - pos++; - } - cBeg = ++pos; + while (inBuffer[pos] != '\"' && inBuffer[pos] != 0) pos++; + if(inBuffer[pos] != 0) ++pos; + cBeg = pos; + + while (inBuffer[pos] != '\"' && inBuffer[pos] != 0) pos++; - while (inBuffer[pos] != '\"' && inBuffer[pos] != 0) - { - pos++; - } len = pos - cBeg; - if (len > maxSize) - { - len = maxSize; - } + if (len > maxSize) len = maxSize; + strncpy(outBuffer, (char *)&inBuffer[cBeg], len); outBuffer[len] = 0; // fprintf(errlog, "_parseString, pos: %i, cBeg: %i, deviceName: %s\n", pos, cBeg, target); @@ -370,80 +377,37 @@ int XPLPro::_parseString(char *outBuffer, char *inBuffer, int parameter, int max int XPLPro::_parseInt(int *outTarget, char *inBuffer, int parameter) { - int cBeg; - int pos = 0; - // search for the selected parameter - for (int i = 1; i < parameter; i++) - { - while (inBuffer[pos] != ',' && inBuffer[pos] != 0) - { - pos++; - } - pos++; - } - // parameter starts here - cBeg = pos; - // search for end of parameter - while (inBuffer[pos] != ',' && inBuffer[pos] != 0 && inBuffer[pos] != XPL_PACKETTRAILER) - { - pos++; - } + int cSt, cEnd; + _seekParm(inBuffer, parameter, cSt, cEnd); // temporarily make parameter null terminated - char holdChar = inBuffer[pos]; - inBuffer[pos] = 0; + char holdChar = inBuffer[cEnd]; + inBuffer[cEnd] = 0; // get integer value from string - *outTarget = atoi((char *)&inBuffer[cBeg]); + *outTarget = atoi((char *)&inBuffer[cSt]); // restore buffer - inBuffer[pos] = holdChar; + inBuffer[cEnd] = holdChar; return 0; } int XPLPro::_parseInt(long *outTarget, char *inBuffer, int parameter) { - int cBeg; - int pos = 0; - for (int i = 1; i < parameter; i++) - { - while (inBuffer[pos] != ',' && inBuffer[pos] != 0) - { - pos++; - } - pos++; - } - cBeg = pos; - while (inBuffer[pos] != ',' && inBuffer[pos] != 0 && inBuffer[pos] != XPL_PACKETTRAILER) - { - pos++; - } - char holdChar = inBuffer[pos]; - inBuffer[pos] = 0; - *outTarget = atoi((char *)&inBuffer[cBeg]); - inBuffer[pos] = holdChar; + int cSt, cEnd; + _seekParm(inBuffer, parameter, cSt, cEnd); + char holdChar = inBuffer[cEnd]; + inBuffer[cEnd] = 0; + *outTarget = atoi((char *)&inBuffer[cSt]); + inBuffer[cEnd] = holdChar; return 0; } int XPLPro::_parseFloat(float *outTarget, char *inBuffer, int parameter) { - int cBeg; - int pos = 0; - for (int i = 1; i < parameter; i++) - { - while (inBuffer[pos] != ',' && inBuffer[pos] != 0) - { - pos++; - } - pos++; - } - cBeg = pos; - while (inBuffer[pos] != ',' && inBuffer[pos] != 0 && inBuffer[pos] != XPL_PACKETTRAILER) - { - pos++; - } - char holdChar = inBuffer[pos]; - inBuffer[pos] = 0; - *outTarget = atof((char *)&inBuffer[cBeg]); - inBuffer[pos] = holdChar; - return 0; + int cSt, cEnd; + _seekParm(inBuffer, parameter, cSt, cEnd); + char holdChar = inBuffer[cEnd]; + inBuffer[cEnd] = 0; + *outTarget = atof((char *)&inBuffer[cSt]); + inBuffer[cEnd] = holdChar; } int XPLPro::registerDataRef(XPString_t *datarefName) diff --git a/XPLPro_Arduino/XPLPro.h b/XPLPro_Arduino/XPLPro.h index 1452847..b80b20d 100644 --- a/XPLPro_Arduino/XPLPro.h +++ b/XPLPro_Arduino/XPLPro.h @@ -241,6 +241,7 @@ class XPLPro void _sendname(); void _sendPacketVoid(int command, int handle); // just a command with a handle void _sendPacketString(int command, const char *str); // send a string + void _seekParm(char* buf, int paramIdx, int& start, int &end); int _parseInt(int *outTarget, char *inBuffer, int parameter); int _parseInt(long *outTarget, char *inBuffer, int parameter); int _parseFloat(float *outTarget, char *inBuffer, int parameter); From 13b102ece088329b985b2ed26ade4a8a76b732f1 Mon Sep 17 00:00:00 2001 From: Giorgio Croci Candiani Date: Fri, 2 Jun 2023 17:26:27 +0200 Subject: [PATCH 02/13] This version of the plugin fixes a minor parsing issue (MG-Discord ch #beta-testers-20230601 18:40) --- XPLPro_Demo/XPLProAbbreviationsDemo.ino | 172 ++++++++++++++++++++++++ XPLPro_Plugin/64/win.xpl | Bin 40960 -> 40960 bytes XPLPro_Plugin/abbreviations.txt | 11 ++ 3 files changed, 183 insertions(+) create mode 100644 XPLPro_Demo/XPLProAbbreviationsDemo.ino diff --git a/XPLPro_Demo/XPLProAbbreviationsDemo.ino b/XPLPro_Demo/XPLProAbbreviationsDemo.ino new file mode 100644 index 0000000..9d99dca --- /dev/null +++ b/XPLPro_Demo/XPLProAbbreviationsDemo.ino @@ -0,0 +1,172 @@ + + +/* + * + * XPLProAbbreviationsDemo + * + * Created by Curiosity Workshop for XPL/Pro arduino->XPlane system. + * + * This sketch was developed and tested on an Arduino Mega. + * + To report problems, download updates and examples, suggest enhancements or get technical support: + + discord: https://discord.gg/RacvaRFsMW + patreon: www.patreon.com/curiosityworkshop + YouTube: https://youtube.com/channel/UCISdHdJIundC-OSVAEPzQIQ + * + * + */ + +#include +#include + +#include // include file for the X-plane direct interface +XPLPro XP(&Serial); // create an instance of it + +LiquidCrystal_I2C lcd(0x26,16,2); + + +long int startTime; + + +#define PIN_GOAROUND 22 // go around button +#define PIN_GEARTOGGLE 23 // pin for gear toggle + +#define PIN_PAUSE 9 // pin to pause xplane +#define PIN_NAVLIGHT 24 // pin for nav light switch +#define PIN_LANDINGLIGHT 7 // pin for landing light switch + + + +int drefBeaconLight; +int drefNavLight, navlightPrevious = -1; +int drefLdgLight; +int drefTaxiLight; +int drefStrobeLight; + +int cmdGearToggle; // a handle for toggling landing gear up and down +int cmdPause; // pause the sim +int cmdToga; // take off/go around + + +void setup() +{ + lcd.init(); + lcd.backlight(); + lcd.setCursor(0,0); + lcd.print("XPLPro Demo!"); + + pinMode(PIN_GEARTOGGLE, INPUT_PULLUP); // if you are doing pin handling yourself you will want a pullup resistor or use the built-in one + pinMode(PIN_NAVLIGHT, INPUT_PULLUP); // otherwise the value will be erratic when the pin is open and nobody likes that. + pinMode(PIN_GOAROUND, INPUT_PULLUP); + pinMode(PIN_LANDINGLIGHT, INPUT_PULLUP); + + pinMode(PIN_PAUSE, INPUT_PULLUP); + + pinMode(LED_BUILTIN, OUTPUT); // built in LED on arduino board for debug and demonstration purposes + + + Serial.begin(XPL_BAUDRATE); // start serial interface. Baudrate is specified in the header, dont change + + /* + needed for initialization. Parameters are: + a texual identifier of your device + your function that will be called when xplane and the plugin are ready for dataref and command registrations + your function that will be called when xplane either shuts down or unloads an aircraft model + your function that will be called when we have requested sends of datarefs that have changed + */ + XP.begin("XPLPro Abbreviation Demo!", &xplRegister, &xplShutdown, &xplInboundHandler); + digitalWrite(LED_BUILTIN, LOW); + + +} + + +void loop() +{ + + + + XP.xloop(); // needs to run every cycle. + +/************************************************************************************************************************************ + * everything after the next line will only occur every 100ms. You can also utilize other time values. + * This helps maintain serial data flow and also helps with switch debounce. + * do NOT add delays anywhere in the loop cycle, it will interfere with the reception of serial data from xplane and the plugin. + ************************************************************************************************************************************ +*/ + + if (millis() - startTime > 100) startTime = millis(); else return; + + +/* + * This reads the status of the assigned pins and triggers commands accordingly. It would be best to use a button library for this for debounce and one-shot purposes + * I am not using one for simplicity in the demo. + */ + if (!digitalRead(PIN_GEARTOGGLE)) XP.commandTrigger(cmdGearToggle); + if (!digitalRead(PIN_GOAROUND)) XP.commandTrigger(cmdToga); + if (!digitalRead(PIN_PAUSE)) XP.commandTrigger(cmdPause); + + + if (digitalRead(PIN_NAVLIGHT) != navlightPrevious) // to conserve the flow of data we should keep track of the previously sent value so we don't send a new one every cycle + { + navlightPrevious = digitalRead(PIN_NAVLIGHT); + XP.datarefWrite(drefNavLight, navlightPrevious); + } + + //landingLights = digitalRead(PIN_LANDINGLIGHT); + + + + + +} + +/* + * This function is the callback function we specified that will be called any time our requested data is sent to us. + * handle is the handle to the dataref. The following values are transfered to the callback through inStruct: + * + * int inData->handle The handle of the incoming dataref + * int inData->element If the dataref is an array style dataref, this is the element of the array + * long inData->inLong long value for datarefs that are long values + * float inData->inFloat float value for datarefs that are float values + */ +void xplInboundHandler(inStruct *inData) +{ + if (inData->handle == drefBeaconLight) + { if (inData->inLong) digitalWrite(LED_BUILTIN, HIGH); // if beacon is on set the builtin led on + else digitalWrite(LED_BUILTIN, LOW); + } + + + + +} + +void xplRegister() // this is the function we set as a callback for when the plugin is ready to receive dataref and command bindings requests +{ + + + drefLdgLight = XP.registerDataRef(F("LTland") ); // "LTland" will be converted to "sim/cockpit/electrical/landing_lights_on" + drefTaxiLight = XP.registerDataRef(F("LTtaxi")); // other abbreviations are listed in the abbreviations.txt file in the plugin folder. + drefBeaconLight = XP.registerDataRef(F("LTbcn")); + drefStrobeLight = XP.registerDataRef(F("LTstrobe")); + drefNavLight = XP.registerDataRef(F("LTnav")); + + +/* + * Now register commands. + * + */ + cmdPause = XP.registerCommand(F("CMDpause") ); + cmdToga = XP.registerCommand(F("CMDtoga") ); + cmdGearToggle = XP.registerCommand(F("CMDgearToggle") ); + + +} + +void xplShutdown() +{ + // if you need to do things when xplane shuts down or unloads an aircraft, do it here. + +} diff --git a/XPLPro_Plugin/64/win.xpl b/XPLPro_Plugin/64/win.xpl index f64866ff3f9a94313f7638f97517fd345d3e543a..11b8afbbcb019dca60c36920a69aa08e9a7fa690 100644 GIT binary patch delta 10938 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 GiT?+|;W5Vm delta 10922 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 diff --git a/XPLPro_Plugin/abbreviations.txt b/XPLPro_Plugin/abbreviations.txt index eb611c2..c0a2682 100644 --- a/XPLPro_Plugin/abbreviations.txt +++ b/XPLPro_Plugin/abbreviations.txt @@ -10,4 +10,15 @@ LTnav = sim/cockpit/electrical/nav_lights_on LTland = sim/cockpit/electrical/landing_lights_on LTstrobe = sim/cockpit/electrical/strobe_lights_on LTtaxi = sim/cockpit/electrical/taxi_light_on +LTtax = sim/cockpit/electrical/taxi_light_on +LTlnd = sim/cockpit/electrical/landing_lights_on +LTnav = sim/cockpit/electrical/nav_lights_on +LTstr = sim/cockpit/electrical/strobe_lights_on + ANmc = sim/cockpit/warnings/annunciators/master_caution + +Commands can be abbreviated as well: + +CMDpause = sim/operation/pause_toggle +CMDtoga = sim/autopilot/take_off_go_around +CMDgearToggle = sim/flight_controls/landing_gear_toggle \ No newline at end of file From 3c147bf927d2ec1e3490a09484820c81cafedbb2 Mon Sep 17 00:00:00 2001 From: Giorgio Croci Candiani Date: Fri, 2 Jun 2023 19:25:41 +0200 Subject: [PATCH 03/13] Changed atoi to atol --- XPLPro_Arduino/XPLPro.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/XPLPro_Arduino/XPLPro.cpp b/XPLPro_Arduino/XPLPro.cpp index cce9bff..0495c0c 100644 --- a/XPLPro_Arduino/XPLPro.cpp +++ b/XPLPro_Arduino/XPLPro.cpp @@ -395,7 +395,7 @@ int XPLPro::_parseInt(long *outTarget, char *inBuffer, int parameter) _seekParm(inBuffer, parameter, cSt, cEnd); char holdChar = inBuffer[cEnd]; inBuffer[cEnd] = 0; - *outTarget = atoi((char *)&inBuffer[cSt]); + *outTarget = atol((char *)&inBuffer[cSt]); inBuffer[cEnd] = holdChar; return 0; } From b80d8b12b1f0dbce0dffb54742897f4445a56368 Mon Sep 17 00:00:00 2001 From: GioCC Date: Tue, 19 Sep 2023 12:50:07 +0200 Subject: [PATCH 04/13] Added plugin source --- XPLPro_Plugin_Source/.gitattributes | 63 + XPLPro_Plugin_Source/.gitignore | 363 ++++ XPLPro_Plugin_Source/Config.cpp | 113 ++ XPLPro_Plugin_Source/Config.h | 46 + XPLPro_Plugin_Source/DataTransfer.cpp | 467 +++++ XPLPro_Plugin_Source/DataTransfer.h | 69 + .../SDK/CHeaders/Widgets/XPStandardWidgets.h | 556 ++++++ .../SDK/CHeaders/Widgets/XPUIGraphics.h | 354 ++++ .../SDK/CHeaders/Widgets/XPWidgetDefs.h | 472 +++++ .../SDK/CHeaders/Widgets/XPWidgetUtils.h | 232 +++ .../SDK/CHeaders/Widgets/XPWidgets.h | 538 ++++++ .../SDK/CHeaders/Wrappers/XPCBroadcaster.cpp | 56 + .../SDK/CHeaders/Wrappers/XPCBroadcaster.h | 38 + .../SDK/CHeaders/Wrappers/XPCDisplay.cpp | 104 ++ .../SDK/CHeaders/Wrappers/XPCDisplay.h | 73 + .../SDK/CHeaders/Wrappers/XPCListener.cpp | 27 + .../SDK/CHeaders/Wrappers/XPCListener.h | 36 + .../SDK/CHeaders/Wrappers/XPCProcessing.cpp | 52 + .../SDK/CHeaders/Wrappers/XPCProcessing.h | 37 + .../SDK/CHeaders/Wrappers/XPCWidget.cpp | 123 ++ .../SDK/CHeaders/Wrappers/XPCWidget.h | 84 + .../Wrappers/XPCWidgetAttachments.cpp | 267 +++ .../CHeaders/Wrappers/XPCWidgetAttachments.h | 146 ++ .../SDK/CHeaders/XPLM/XPLMCamera.h | 167 ++ .../SDK/CHeaders/XPLM/XPLMDataAccess.h | 716 +++++++ .../SDK/CHeaders/XPLM/XPLMDefs.h | 514 +++++ .../SDK/CHeaders/XPLM/XPLMDisplay.h | 1477 +++++++++++++++ .../SDK/CHeaders/XPLM/XPLMGraphics.h | 437 +++++ .../SDK/CHeaders/XPLM/XPLMInstance.h | 136 ++ .../SDK/CHeaders/XPLM/XPLMMap.h | 631 +++++++ .../SDK/CHeaders/XPLM/XPLMMenus.h | 290 +++ .../SDK/CHeaders/XPLM/XPLMNavigation.h | 362 ++++ .../SDK/CHeaders/XPLM/XPLMPlanes.h | 287 +++ .../SDK/CHeaders/XPLM/XPLMPlugin.h | 422 +++++ .../SDK/CHeaders/XPLM/XPLMProcessing.h | 264 +++ .../SDK/CHeaders/XPLM/XPLMScenery.h | 450 +++++ .../SDK/CHeaders/XPLM/XPLMUtilities.h | 970 ++++++++++ .../SDK/Delphi/Widgets/XPStandardWidgets.pas | 470 +++++ .../SDK/Delphi/Widgets/XPUIGraphics.pas | 342 ++++ .../SDK/Delphi/Widgets/XPWidgetDefs.pas | 427 +++++ .../SDK/Delphi/Widgets/XPWidgetUtils.pas | 197 ++ .../SDK/Delphi/Widgets/XPWidgets.pas | 527 ++++++ .../SDK/Delphi/XPLM/XPLMCamera.pas | 155 ++ .../SDK/Delphi/XPLM/XPLMDataAccess.pas | 690 +++++++ .../SDK/Delphi/XPLM/XPLMDefs.pas | 438 +++++ .../SDK/Delphi/XPLM/XPLMDisplay.pas | 1452 +++++++++++++++ .../SDK/Delphi/XPLM/XPLMGraphics.pas | 424 +++++ .../SDK/Delphi/XPLM/XPLMInstance.pas | 125 ++ .../SDK/Delphi/XPLM/XPLMMap.pas | 611 ++++++ .../SDK/Delphi/XPLM/XPLMMenus.pas | 277 +++ .../SDK/Delphi/XPLM/XPLMNavigation.pas | 350 ++++ .../SDK/Delphi/XPLM/XPLMPlanes.pas | 278 +++ .../SDK/Delphi/XPLM/XPLMPlugin.pas | 413 ++++ .../SDK/Delphi/XPLM/XPLMProcessing.pas | 254 +++ .../SDK/Delphi/XPLM/XPLMScenery.pas | 434 +++++ .../SDK/Delphi/XPLM/XPLMUtilities.pas | 951 ++++++++++ .../SDK/Libraries/Mac/XPLM.framework/XPLM | Bin 0 -> 214288 bytes .../Mac/XPWidgets.framework/XPWidgets | Bin 0 -> 48768 bytes XPLPro_Plugin_Source/SDK/README.txt | 197 ++ .../SDK/CHeaders/Widgets/XPStandardWidgets.h | 556 ++++++ .../SDK/SDK/CHeaders/Widgets/XPUIGraphics.h | 354 ++++ .../SDK/SDK/CHeaders/Widgets/XPWidgetDefs.h | 472 +++++ .../SDK/SDK/CHeaders/Widgets/XPWidgetUtils.h | 232 +++ .../SDK/SDK/CHeaders/Widgets/XPWidgets.h | 538 ++++++ .../SDK/CHeaders/Wrappers/XPCBroadcaster.cpp | 56 + .../SDK/CHeaders/Wrappers/XPCBroadcaster.h | 38 + .../SDK/SDK/CHeaders/Wrappers/XPCDisplay.cpp | 104 ++ .../SDK/SDK/CHeaders/Wrappers/XPCDisplay.h | 73 + .../SDK/SDK/CHeaders/Wrappers/XPCListener.cpp | 27 + .../SDK/SDK/CHeaders/Wrappers/XPCListener.h | 36 + .../SDK/CHeaders/Wrappers/XPCProcessing.cpp | 52 + .../SDK/SDK/CHeaders/Wrappers/XPCProcessing.h | 37 + .../SDK/SDK/CHeaders/Wrappers/XPCWidget.cpp | 123 ++ .../SDK/SDK/CHeaders/Wrappers/XPCWidget.h | 84 + .../Wrappers/XPCWidgetAttachments.cpp | 267 +++ .../CHeaders/Wrappers/XPCWidgetAttachments.h | 146 ++ .../SDK/SDK/CHeaders/XPLM/XPLMCamera.h | 167 ++ .../SDK/SDK/CHeaders/XPLM/XPLMDataAccess.h | 716 +++++++ .../SDK/SDK/CHeaders/XPLM/XPLMDefs.h | 514 +++++ .../SDK/SDK/CHeaders/XPLM/XPLMDisplay.h | 1658 +++++++++++++++++ .../SDK/SDK/CHeaders/XPLM/XPLMGraphics.h | 437 +++++ .../SDK/SDK/CHeaders/XPLM/XPLMInstance.h | 136 ++ .../SDK/SDK/CHeaders/XPLM/XPLMMap.h | 628 +++++++ .../SDK/SDK/CHeaders/XPLM/XPLMMenus.h | 290 +++ .../SDK/SDK/CHeaders/XPLM/XPLMNavigation.h | 362 ++++ .../SDK/SDK/CHeaders/XPLM/XPLMPlanes.h | 287 +++ .../SDK/SDK/CHeaders/XPLM/XPLMPlugin.h | 422 +++++ .../SDK/SDK/CHeaders/XPLM/XPLMProcessing.h | 264 +++ .../SDK/SDK/CHeaders/XPLM/XPLMScenery.h | 450 +++++ .../SDK/SDK/CHeaders/XPLM/XPLMUtilities.h | 970 ++++++++++ .../SDK/Delphi/Widgets/XPStandardWidgets.pas | 470 +++++ .../SDK/SDK/Delphi/Widgets/XPUIGraphics.pas | 342 ++++ .../SDK/SDK/Delphi/Widgets/XPWidgetDefs.pas | 427 +++++ .../SDK/SDK/Delphi/Widgets/XPWidgetUtils.pas | 197 ++ .../SDK/SDK/Delphi/Widgets/XPWidgets.pas | 527 ++++++ .../SDK/SDK/Delphi/XPLM/XPLMCamera.pas | 155 ++ .../SDK/SDK/Delphi/XPLM/XPLMDataAccess.pas | 690 +++++++ .../SDK/SDK/Delphi/XPLM/XPLMDefs.pas | 438 +++++ .../SDK/SDK/Delphi/XPLM/XPLMDisplay.pas | 1630 ++++++++++++++++ .../SDK/SDK/Delphi/XPLM/XPLMGraphics.pas | 424 +++++ .../SDK/SDK/Delphi/XPLM/XPLMInstance.pas | 125 ++ .../SDK/SDK/Delphi/XPLM/XPLMMap.pas | 608 ++++++ .../SDK/SDK/Delphi/XPLM/XPLMMenus.pas | 277 +++ .../SDK/SDK/Delphi/XPLM/XPLMNavigation.pas | 350 ++++ .../SDK/SDK/Delphi/XPLM/XPLMPlanes.pas | 278 +++ .../SDK/SDK/Delphi/XPLM/XPLMPlugin.pas | 413 ++++ .../SDK/SDK/Delphi/XPLM/XPLMProcessing.pas | 254 +++ .../SDK/SDK/Delphi/XPLM/XPLMScenery.pas | 434 +++++ .../SDK/SDK/Delphi/XPLM/XPLMUtilities.pas | 951 ++++++++++ .../SDK/SDK/Libraries/Mac/XPLM.framework/XPLM | Bin 0 -> 566176 bytes .../Mac/XPWidgets.framework/XPWidgets | Bin 0 -> 195312 bytes XPLPro_Plugin_Source/SDK/SDK/README.txt | 222 +++ XPLPro_Plugin_Source/SDK/SDK/license.txt | 27 + .../CHeaders/Widgets/XPStandardWidgets.h | 556 ++++++ .../SDKold/CHeaders/Widgets/XPUIGraphics.h | 354 ++++ .../SDKold/CHeaders/Widgets/XPWidgetDefs.h | 472 +++++ .../SDKold/CHeaders/Widgets/XPWidgetUtils.h | 232 +++ .../SDK/SDKold/CHeaders/Widgets/XPWidgets.h | 538 ++++++ .../CHeaders/Wrappers/XPCBroadcaster.cpp | 56 + .../SDKold/CHeaders/Wrappers/XPCBroadcaster.h | 38 + .../SDKold/CHeaders/Wrappers/XPCDisplay.cpp | 104 ++ .../SDK/SDKold/CHeaders/Wrappers/XPCDisplay.h | 73 + .../SDKold/CHeaders/Wrappers/XPCListener.cpp | 27 + .../SDKold/CHeaders/Wrappers/XPCListener.h | 36 + .../CHeaders/Wrappers/XPCProcessing.cpp | 52 + .../SDKold/CHeaders/Wrappers/XPCProcessing.h | 37 + .../SDKold/CHeaders/Wrappers/XPCWidget.cpp | 123 ++ .../SDK/SDKold/CHeaders/Wrappers/XPCWidget.h | 84 + .../Wrappers/XPCWidgetAttachments.cpp | 267 +++ .../CHeaders/Wrappers/XPCWidgetAttachments.h | 146 ++ .../SDK/SDKold/CHeaders/XPLM/XPLMCamera.h | 167 ++ .../SDK/SDKold/CHeaders/XPLM/XPLMDataAccess.h | 716 +++++++ .../SDK/SDKold/CHeaders/XPLM/XPLMDefs.h | 514 +++++ .../SDK/SDKold/CHeaders/XPLM/XPLMDisplay.h | 1658 +++++++++++++++++ .../SDK/SDKold/CHeaders/XPLM/XPLMGraphics.h | 437 +++++ .../SDK/SDKold/CHeaders/XPLM/XPLMInstance.h | 136 ++ .../SDK/SDKold/CHeaders/XPLM/XPLMMap.h | 628 +++++++ .../SDK/SDKold/CHeaders/XPLM/XPLMMenus.h | 290 +++ .../SDK/SDKold/CHeaders/XPLM/XPLMNavigation.h | 362 ++++ .../SDK/SDKold/CHeaders/XPLM/XPLMPlanes.h | 287 +++ .../SDK/SDKold/CHeaders/XPLM/XPLMPlugin.h | 422 +++++ .../SDK/SDKold/CHeaders/XPLM/XPLMProcessing.h | 264 +++ .../SDK/SDKold/CHeaders/XPLM/XPLMScenery.h | 450 +++++ .../SDK/SDKold/CHeaders/XPLM/XPLMUtilities.h | 970 ++++++++++ .../Delphi/Widgets/XPStandardWidgets.pas | 470 +++++ .../SDKold/Delphi/Widgets/XPUIGraphics.pas | 342 ++++ .../SDKold/Delphi/Widgets/XPWidgetDefs.pas | 427 +++++ .../SDKold/Delphi/Widgets/XPWidgetUtils.pas | 197 ++ .../SDK/SDKold/Delphi/Widgets/XPWidgets.pas | 527 ++++++ .../SDK/SDKold/Delphi/XPLM/XPLMCamera.pas | 155 ++ .../SDK/SDKold/Delphi/XPLM/XPLMDataAccess.pas | 690 +++++++ .../SDK/SDKold/Delphi/XPLM/XPLMDefs.pas | 438 +++++ .../SDK/SDKold/Delphi/XPLM/XPLMDisplay.pas | 1630 ++++++++++++++++ .../SDK/SDKold/Delphi/XPLM/XPLMGraphics.pas | 424 +++++ .../SDK/SDKold/Delphi/XPLM/XPLMInstance.pas | 125 ++ .../SDK/SDKold/Delphi/XPLM/XPLMMap.pas | 608 ++++++ .../SDK/SDKold/Delphi/XPLM/XPLMMenus.pas | 277 +++ .../SDK/SDKold/Delphi/XPLM/XPLMNavigation.pas | 350 ++++ .../SDK/SDKold/Delphi/XPLM/XPLMPlanes.pas | 278 +++ .../SDK/SDKold/Delphi/XPLM/XPLMPlugin.pas | 413 ++++ .../SDK/SDKold/Delphi/XPLM/XPLMProcessing.pas | 254 +++ .../SDK/SDKold/Delphi/XPLM/XPLMScenery.pas | 434 +++++ .../SDK/SDKold/Delphi/XPLM/XPLMUtilities.pas | 951 ++++++++++ .../SDKold/Libraries/Mac/XPLM.framework/XPLM | Bin 0 -> 566176 bytes .../Mac/XPWidgets.framework/XPWidgets | Bin 0 -> 195312 bytes XPLPro_Plugin_Source/SDK/SDKold/README.txt | 222 +++ XPLPro_Plugin_Source/SDK/SDKold/license.txt | 27 + XPLPro_Plugin_Source/SDK/license.txt | 27 + XPLPro_Plugin_Source/SerialClass.cpp | 168 ++ XPLPro_Plugin_Source/SimData.vcxproj | 303 +++ XPLPro_Plugin_Source/StatusWindow.cpp | 176 ++ XPLPro_Plugin_Source/StatusWindow.h | 16 + XPLPro_Plugin_Source/XPLDevice.cpp | 678 +++++++ XPLPro_Plugin_Source/XPLDevice.h | 57 + XPLPro_Plugin_Source/XPLPro.sln | 48 + XPLPro_Plugin_Source/XPLProCommon.h | 70 + XPLPro_Plugin_Source/XPLProPlugin.cpp | 363 ++++ XPLPro_Plugin_Source/XPLProPlugin.h | 17 + XPLPro_Plugin_Source/abbreviations.cpp | 89 + XPLPro_Plugin_Source/abbreviations.h | 18 + XPLPro_Plugin_Source/libconfig.h | 355 ++++ XPLPro_Plugin_Source/monitorwindow.h | 11 + XPLPro_Plugin_Source/serialclass.h | 50 + 183 files changed, 62367 insertions(+) create mode 100644 XPLPro_Plugin_Source/.gitattributes create mode 100644 XPLPro_Plugin_Source/.gitignore create mode 100644 XPLPro_Plugin_Source/Config.cpp create mode 100644 XPLPro_Plugin_Source/Config.h create mode 100644 XPLPro_Plugin_Source/DataTransfer.cpp create mode 100644 XPLPro_Plugin_Source/DataTransfer.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPStandardWidgets.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPUIGraphics.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgetDefs.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgetUtils.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgets.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCBroadcaster.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCDisplay.cpp create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCDisplay.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCListener.cpp create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCListener.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCProcessing.cpp create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCProcessing.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidget.cpp create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidget.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMCamera.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDataAccess.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDefs.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDisplay.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMGraphics.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMInstance.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMMap.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMMenus.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMNavigation.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMPlanes.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMPlugin.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMProcessing.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMScenery.h create mode 100644 XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMUtilities.h create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPStandardWidgets.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPUIGraphics.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgetDefs.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgetUtils.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgets.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMCamera.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDataAccess.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDefs.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDisplay.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMGraphics.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMInstance.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMMap.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMMenus.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMNavigation.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMPlanes.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMPlugin.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMProcessing.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMScenery.pas create mode 100644 XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMUtilities.pas create mode 100644 XPLPro_Plugin_Source/SDK/Libraries/Mac/XPLM.framework/XPLM create mode 100644 XPLPro_Plugin_Source/SDK/Libraries/Mac/XPWidgets.framework/XPWidgets create mode 100644 XPLPro_Plugin_Source/SDK/README.txt create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPStandardWidgets.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPUIGraphics.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgetDefs.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgetUtils.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgets.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCBroadcaster.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCDisplay.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCDisplay.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCListener.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCListener.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCProcessing.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCProcessing.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidget.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidget.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMCamera.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDataAccess.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDefs.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDisplay.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMGraphics.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMInstance.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMMap.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMMenus.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMNavigation.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMPlanes.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMPlugin.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMProcessing.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMScenery.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMUtilities.h create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPStandardWidgets.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPUIGraphics.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgetDefs.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgetUtils.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgets.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMCamera.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDataAccess.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDefs.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDisplay.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMGraphics.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMInstance.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMMap.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMMenus.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMNavigation.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMPlanes.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMPlugin.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMProcessing.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMScenery.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMUtilities.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Libraries/Mac/XPLM.framework/XPLM create mode 100644 XPLPro_Plugin_Source/SDK/SDK/Libraries/Mac/XPWidgets.framework/XPWidgets create mode 100644 XPLPro_Plugin_Source/SDK/SDK/README.txt create mode 100644 XPLPro_Plugin_Source/SDK/SDK/license.txt create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPStandardWidgets.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPUIGraphics.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgetDefs.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgetUtils.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgets.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCBroadcaster.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCBroadcaster.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCDisplay.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCDisplay.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCListener.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCListener.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCProcessing.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCProcessing.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidget.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidget.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidgetAttachments.cpp create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidgetAttachments.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMCamera.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDataAccess.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDefs.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDisplay.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMGraphics.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMInstance.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMMap.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMMenus.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMNavigation.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMPlanes.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMPlugin.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMProcessing.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMScenery.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMUtilities.h create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPStandardWidgets.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPUIGraphics.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgetDefs.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgetUtils.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgets.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMCamera.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDataAccess.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDefs.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDisplay.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMGraphics.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMInstance.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMMap.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMMenus.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMNavigation.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMPlanes.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMPlugin.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMProcessing.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMScenery.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMUtilities.pas create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Libraries/Mac/XPLM.framework/XPLM create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/Libraries/Mac/XPWidgets.framework/XPWidgets create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/README.txt create mode 100644 XPLPro_Plugin_Source/SDK/SDKold/license.txt create mode 100644 XPLPro_Plugin_Source/SDK/license.txt create mode 100644 XPLPro_Plugin_Source/SerialClass.cpp create mode 100644 XPLPro_Plugin_Source/SimData.vcxproj create mode 100644 XPLPro_Plugin_Source/StatusWindow.cpp create mode 100644 XPLPro_Plugin_Source/StatusWindow.h create mode 100644 XPLPro_Plugin_Source/XPLDevice.cpp create mode 100644 XPLPro_Plugin_Source/XPLDevice.h create mode 100644 XPLPro_Plugin_Source/XPLPro.sln create mode 100644 XPLPro_Plugin_Source/XPLProCommon.h create mode 100644 XPLPro_Plugin_Source/XPLProPlugin.cpp create mode 100644 XPLPro_Plugin_Source/XPLProPlugin.h create mode 100644 XPLPro_Plugin_Source/abbreviations.cpp create mode 100644 XPLPro_Plugin_Source/abbreviations.h create mode 100644 XPLPro_Plugin_Source/libconfig.h create mode 100644 XPLPro_Plugin_Source/monitorwindow.h create mode 100644 XPLPro_Plugin_Source/serialclass.h diff --git a/XPLPro_Plugin_Source/.gitattributes b/XPLPro_Plugin_Source/.gitattributes new file mode 100644 index 0000000..1ff0c42 --- /dev/null +++ b/XPLPro_Plugin_Source/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/XPLPro_Plugin_Source/.gitignore b/XPLPro_Plugin_Source/.gitignore new file mode 100644 index 0000000..9491a2f --- /dev/null +++ b/XPLPro_Plugin_Source/.gitignore @@ -0,0 +1,363 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/XPLPro_Plugin_Source/Config.cpp b/XPLPro_Plugin_Source/Config.cpp new file mode 100644 index 0000000..7c2288b --- /dev/null +++ b/XPLPro_Plugin_Source/Config.cpp @@ -0,0 +1,113 @@ + +#include +//#include "XPLDirectCommon.h" + +#include "Config.h" + +Config::Config(char *inFileName) +{ + + strncpy(_cfgFileName, inFileName, 512); + _cfgFileName[511] = 0; + + FILE* cfgFile; + _validConfig = false; + + + if (cfgFile = fopen(_cfgFileName, "r")) + fclose(cfgFile); + else + { + fprintf(errlog, "***Configuration file %s doesn't exist, please replace...\n", _cfgFileName); + return; + // createNewConfigFile(); + } + + fprintf(errlog, "Opening configuration file %s... ", _cfgFileName); + + //config_setting_t* root, * setting, * group, * array; + config_init(&_cfg); + + if (!config_read_file(&_cfg, _cfgFileName)) + { + fprintf(errlog, "Error: %s Line:%i\r\n", config_error_text(&_cfg), config_error_line(&_cfg)); + config_destroy(&_cfg); + + } + else + fprintf(errlog, "Success.\n"); + + _validConfig = true; + +} + +Config::~Config() +{ + if (_validConfig) return; + + config_write_file(&_cfg, _cfgFileName); + + config_destroy(&_cfg); +} + + +// commit changes to the configuration file +void Config::saveFile(void) +{ + if (!config_write_file(&_cfg, _cfgFileName)) + { + fprintf(errlog, "Config::saveFile Error: %s Line:%i\r\n", config_error_text(&_cfg), config_error_line(&_cfg)); + return; + } + else + { + // fprintf(errlog, "Config::saveFile: Success updating configuration file.\n"); + + + } +} + + +// getSerialLogFlag +int Config::getSerialLogFlag(void) +{ + int flag = 0; + + if (!_validConfig) return 0; + + if (config_lookup_int(&_cfg, "XPLProPlugin.logSerialData", &flag) == CONFIG_TRUE) + fprintf(errlog, "Config module found XPLProPlugin.logSerialData value %i\r\n", flag); + else + fprintf(errlog, "*** Config module returned CONFIG_FALSE looking up value XPLProPlugin.logSerialData \r\n"); + + return flag; +} + +void Config::setSerialLogFlag(int flag) +{ + if (!_validConfig) return; + + config_setting_t* flagSetting = config_lookup(&_cfg, "XPLProPlugin.logSerialData"); + + if (flagSetting == NULL) + { + fprintf(errlog, "*** Config module unable to locate path XPLProPlugin.logSerialData during write\r\n"); + return; + } + + if (config_setting_set_int(flagSetting, flag) == CONFIG_TRUE) + fprintf(errlog, "Config module set XPLProPlugin.logSerialData to value %i\r\n", flag); + else + fprintf(errlog, "***Config module returned error setting XPLProPlugin.logSerialData to value %i\r\n", flag); +} + + + + + +/* + +Stuff related to components + +*/ + diff --git a/XPLPro_Plugin_Source/Config.h b/XPLPro_Plugin_Source/Config.h new file mode 100644 index 0000000..4574fea --- /dev/null +++ b/XPLPro_Plugin_Source/Config.h @@ -0,0 +1,46 @@ +#pragma once +#ifndef CONFIGCLASS_H_INCLUDED +#define CONFIGCLASS_H_INCLUDED + +#include "libconfig.h" + + + +extern FILE* errlog; + +class Config +{ +private: + + char _cfgFileName[512]; + + config_t _cfg; + + // void createNewConfigFile(void); + + + +public: + + Config(char *inFileName); + ~Config(); + void saveFile(void); + + int getSerialLogFlag(void); + void setSerialLogFlag(int); + + // stuff for components + int getComponentCount(void); + int Config::getComponentInfo(int element, int* type, const char** name, const char** board, int* pinCount, int* linkCount); + void setComponentInfo(int element, int* type, const char* name, const char* board, const char* dataref, int arrayElement); + int getComponentPinInfo(int componentElement, int pinElement, const char** pinName); + + int Config::getComponentLinkInfo(int componentIndex, int linkIndex, char* inName, const char** outData); + int Config::getComponentLinkInfo(int componentIndex, int linkIndex, char* inName, int* outData); + + // local globals + int _validConfig; +}; + +#endif + diff --git a/XPLPro_Plugin_Source/DataTransfer.cpp b/XPLPro_Plugin_Source/DataTransfer.cpp new file mode 100644 index 0000000..bd47a08 --- /dev/null +++ b/XPLPro_Plugin_Source/DataTransfer.cpp @@ -0,0 +1,467 @@ +#define XPLM200 + + + + +#include "XPLProCommon.h" + +#include "XPLMPlugin.h" +#include "XPLMDataAccess.h" +#include "XPLMDisplay.h" +#include "XPLMGraphics.h" +#include "XPLMMenus.h" + +#include "XPWidgets.h" +#include "XPStandardWidgets.h" + +#include "XPLMUtilities.h" +#include "XPLMProcessing.h" + +#include "XPLMCamera.h" +#include "XPUIGraphics.h" +#include "XPWidgetUtils.h" + + +#include "XPLProPlugin.h" +#include "XPLDevice.h" + +#include "DataTransfer.h" + +#include + + + +int refHandleCounter = 0; +int cmdHandleCounter = 0; + + +long int packetsSent; +long int packetsReceived; + +int validPorts = 0; + +extern FILE* errlog; +extern FILE* serialLogFile; +extern float elapsedTime; +extern int lastRefSent; +extern int lastRefElementSent; + + +CommandBinding myCommands[XPL_MAXCOMMANDS_PC]; +DataRefBinding myBindings[XPL_MAXDATAREFS_PC]; +XPLDevice* myXPLDevices[XPLDEVICES_MAXDEVICES]; + +/**************************************************************************************/ +/* disengage -- unregister all datarefs and close all com ports */ +/**************************************************************************************/ +void disengageDevices(void) +{ + sendExitMessage(); + + for (int i = 0; i < XPLDEVICES_MAXDEVICES; i++) + { + + if (myXPLDevices[i]) + { + myXPLDevices[i]->port->shutDown(); + delete myXPLDevices[i]->port; + delete myXPLDevices[i]; + myXPLDevices[i] = NULL; + } + } + + validPorts = 0; + + for (int i = 0; i < refHandleCounter; i++) + { + myBindings[i].deviceIndex = -1; + myBindings[i].bindingActive = 0; + myBindings[i].Handle = -1; + myBindings[i].scaleFlag = 0; + + for (int j = 0; j < XPLMAX_ELEMENTS; j++) + { + myBindings[i].readFlag[j] = 0; + } + + XPLMUnregisterDataAccessor(myBindings[i].xplaneDataRefHandle); // deregister with xplane + myBindings[i].xplaneDataRefTypeID = 0; + myBindings[i].xplaneDataRefName[0] = NULL; + if (myBindings[i].currentSents[0] != NULL) + { + free(myBindings[i].currentSents[0]); + myBindings[i].currentSents[0] = NULL; + } + + } + + refHandleCounter = 0; + + for (int i = 0; i < cmdHandleCounter; i++) + { + myCommands[i].deviceIndex = -1; + myCommands[i].bindingActive = 0; + myCommands[i].Handle = -1; + myCommands[i].xplaneCommandHandle = NULL; + myCommands[i].xplaneCommandName[0] = NULL; + + } + + cmdHandleCounter = 0; + + +} + +/* +* Searches com ports for devices, then queries for datarefs and commands. +*/ +void engageDevices(void) +{ + fprintf(errlog, "engageDevices: started...\n"); + findDevices(); + activateDevices(); + //_updateDataRefs(1); // 1 represents to force updates to the devices + //sendRefreshRequest(); + +} + +/**************************************************************************************/ +/* _updateDataRefs -- get current dataref values for all registered datarefs */ +/**************************************************************************************/ +void _updateDataRefs(int forceUpdate) +{ + + int newVall; + float newValf; + double newValD; + + char writeBuffer[XPLMAX_PACKETSIZE]; + char stringBuffer[XPLMAX_PACKETSIZE - 5]; + + + + for (int i = 0; i < refHandleCounter; i++) + { + if (myBindings[i].bindingActive && myBindings[i].readFlag[0]) // todo: this needs to check all possible readFlags + { + + // if (elapsedTime - myXPLDevices[myBindings[i].deviceIndex].lastSendTime < myXPLDevices[myBindings[i].deviceIndex].minTimeBetweenFrames/1000 && !forceUpdate) + // break; + if (myBindings[i].xplaneDataRefTypeID & xplmType_Int) // process for datarefs of type int + { + newVall = (long int)XPLMGetDatai(myBindings[i].xplaneDataRefHandle); + + if (newVall != myBindings[i].currentSentl[0] || forceUpdate) + { + lastRefSent = i; + myBindings[i].currentSentl[0] = newVall; + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",%i,%ld", i, newVall); + myXPLDevices[myBindings[i].deviceIndex]->_writePacket(XPLCMD_DATAREFUPDATEINT, writeBuffer); + myXPLDevices[myBindings[i].deviceIndex]->lastSendTime = elapsedTime; + + // fprintf(errlog, "using packet: %s\r\n", writeBuffer); + + } + + } + + if (myBindings[i].xplaneDataRefTypeID & xplmType_IntArray) // process for datarefs of type int Array + { + for (int j = 0; j < XPLMAX_ELEMENTS; j++) // todo, this method should be something better + { + XPLMGetDatavi(myBindings[i].xplaneDataRefHandle, &newVall, j, 1); + if (myBindings[i].precision) newVall = ((int)(newVall / myBindings[i].precision) * myBindings[i].precision); + if (newVall != myBindings[i].currentSentl[j] || forceUpdate) + { + lastRefSent = i; + lastRefElementSent = j; + myBindings[i].currentSentl[j] = newVall; + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",%i,%ld,%i", i, newVall,j); + myXPLDevices[myBindings[i].deviceIndex]->_writePacket(XPLCMD_DATAREFUPDATEINTARRAY, writeBuffer); + myXPLDevices[myBindings[i].deviceIndex]->lastSendTime = elapsedTime; + + // fprintf(errlog, "using packet: %s\r\n", writeBuffer); + } + } + } + + + if (myBindings[i].xplaneDataRefTypeID & xplmType_Float) // process for datarefs of type float + { + + newValf = (float)XPLMGetDataf(myBindings[i].xplaneDataRefHandle); + + // fprintf(errlog, "updating dataRef %s with value %f...\r\n ", myBindings[i].xplaneDataRefName, newValf); + if (myBindings[i].precision) newValf = ((int)(newValf / myBindings[i].precision) * myBindings[i].precision); + + if (newValf != myBindings[i].currentSentf[0] || forceUpdate) + { + lastRefSent = i; + myBindings[i].currentSentf[0] = newValf; + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",%i,%f", i, newValf); + myXPLDevices[myBindings[i].deviceIndex]->_writePacket(XPLCMD_DATAREFUPDATEFLOAT, writeBuffer); + myXPLDevices[myBindings[i].deviceIndex]->lastSendTime = elapsedTime; + + // fprintf(errlog, "using packet: %s\r\n", writeBuffer); + + } + + } + + + if (myBindings[i].xplaneDataRefTypeID & xplmType_FloatArray) // process for datarefs of type float (array) + { + + + for (int j = 0; j < XPLMAX_ELEMENTS; j++) + { + XPLMGetDatavf(myBindings[i].xplaneDataRefHandle, &newValf, j, 1); + if (myBindings[i].precision) newValf = ((int)(newValf / myBindings[i].precision) * myBindings[i].precision); + + if (newValf != myBindings[i].currentSentf[j] || forceUpdate) + { + lastRefSent = i; + lastRefElementSent = j; + myBindings[i].currentSentf[j] = newValf; + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",%i,%f,%i", i, newValf,j); + myXPLDevices[myBindings[i].deviceIndex]->_writePacket(XPLCMD_DATAREFUPDATEFLOATARRAY, writeBuffer); + myXPLDevices[myBindings[i].deviceIndex]->lastSendTime = elapsedTime; + + // fprintf(errlog, "using packet: %s\r\n", writeBuffer); + + } + } + + } + + if (myBindings[i].xplaneDataRefTypeID & xplmType_Double) // process for datarefs of type double + { + + newValD = (double)XPLMGetDatad(myBindings[i].xplaneDataRefHandle); + + // fprintf(errlog, "updating dataRef %s with value %f...\r\n ", myBindings[i].xplaneDataRefName, newValf); + if (myBindings[i].precision) newValD = ((int)(newValD / myBindings[i].precision) * myBindings[i].precision); + + if (newValD != myBindings[i].currentSentD[0] || forceUpdate) + { + lastRefSent = i; + myBindings[i].currentSentD[0] = newValD; + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",%i,%f", i, newValD); + myXPLDevices[myBindings[i].deviceIndex]->_writePacket(XPLCMD_DATAREFUPDATEFLOAT, writeBuffer); + myXPLDevices[myBindings[i].deviceIndex]->lastSendTime = elapsedTime; + + // fprintf(errlog, "using packet: %s\r\n", writeBuffer); + + } + + } + + if (myBindings[i].xplaneDataRefTypeID & xplmType_Data) // process for datarefs of type Data (strings) + { + + newVall = (long int)XPLMGetDatab(myBindings[i].xplaneDataRefHandle, stringBuffer, 0, XPLMAX_PACKETSIZE - 5); + //stringBuffer[newVall] = 0; // null terminate + // fprintf(errlog, "updating dataRef %s with value %i...\r\n ", myBindings[i].xplaneDataRefName, newVall); + + if (memcmp(myBindings[i].currentSents[0], stringBuffer, newVall) || forceUpdate) + { + lastRefSent = i; + memcpy(myBindings[i].currentSents[0], stringBuffer, newVall); + sprintf(writeBuffer, ",%i,", i); + + memcpy(&writeBuffer[3], stringBuffer, newVall); + myXPLDevices[myBindings[i].deviceIndex]->_writePacketN(XPLCMD_DATAREFUPDATESTRING, writeBuffer, newVall + 3); + myXPLDevices[myBindings[i].deviceIndex]->lastSendTime = elapsedTime; + + // fprintf(errlog, "Updating dataref %s with packet: %s length: %i\r\n", myBindings[i].xplaneDataRefName, writeBuffer, newVall); + + + } + + } + } + + } + + +} + +/* + _updateCommands -- make sure commands are all updated. + */ +void _updateCommands(void) +{ + + + for (int i = 0; i < cmdHandleCounter; i++) + { + if (myCommands[i].bindingActive && myCommands[i].accumulator > 0) + { + + XPLMCommandOnce(myCommands[i].xplaneCommandHandle); + myCommands[i].accumulator--; + if (myCommands[i].accumulator < 0) myCommands[i].accumulator = 0; + + + } + + } + + +} + +/**************************************************************************************/ +/* activateDevices -- request dataref bindings from all active devices */ +/**************************************************************************************/ +void activateDevices(void) +{ + + fprintf(errlog, "XPLPro: Activating Devices... \n"); + + for (int i = 0; i < XPLDEVICES_MAXDEVICES; i++) + { + if (!myXPLDevices[i]) break; + + fprintf(errlog, "Requesting dataRef or Command registrations from port %s on device [%i]: %s\n", myXPLDevices[i]->port->portName, i, myXPLDevices[i]->deviceName); + myXPLDevices[i]->_writePacket(XPLCMD_SENDREQUEST, ""); + + } + +} + +/* + findDevices -- Scan for XPLPro devices and fills array with active devices +*/ + +int findDevices(void) +{ + time_t startTime; + serialClass* port; + validPorts = 0; + + fprintf(errlog, "Searching Com Ports... "); + + for (UINT i = 1; i < 256; i++) + { + port = new serialClass; + + if (port->begin(i) == i) + { + + fprintf(errlog, "\nFound valid port %s. Attemping poll for XPLPro device... ", port->portName); + myXPLDevices[validPorts] = new XPLDevice(validPorts); + myXPLDevices[validPorts]->port = port; + + if (myXPLDevices[validPorts]->_writePacket(XPLCMD_SENDNAME, "")) + fprintf(errlog, "Valid write operation, seems OK\n"); + + + startTime = time(NULL); + + while (difftime(time(NULL), startTime) < XPL_TIMEOUT_SECONDS && !myXPLDevices[validPorts]->isActive()) _processSerial(); + + if (!myXPLDevices[validPorts]->isActive()) + { + fprintf(errlog, "No response after %i seconds\n", XPL_TIMEOUT_SECONDS); + XPLMDebugString("."); + port->shutDown(); + delete myXPLDevices[validPorts]; + delete port; + //myXPLDevices[validPorts]->comPortName[0] = 0; + } + + else + { + myXPLDevices[validPorts]->readBuffer[0] = '\0'; + fprintf(errlog, " Device [%i] on %s identifies as an XPLPro device named: %s\n", validPorts, port->portName, myXPLDevices[validPorts]->deviceName); + + validPorts++; + } + + } + else + { + port->shutDown(); + delete port; + } + + } + + + //delete myXPLDevices[validPorts]; + XPLMDebugString(" Done Searching Com Ports\n"); + fprintf(errlog, "Total of %i compatible devices were found. \n\n", validPorts); + return 0; +} + + +void _processSerial() +{ + int port = 0; + + while (myXPLDevices[port] && port < XPLDEVICES_MAXDEVICES) + { + //fprintf(errlog, "working on xpldevice %i ...", port); + + myXPLDevices[port]->processSerial(); + + port++; + } +} + +/* + sendRefreshRequest -- request writable datarefs be refreshed +*/ + +void sendRefreshRequest(void) +{ + for (int i = 0; i < XPLDEVICES_MAXDEVICES; i++) + { + if (myXPLDevices[i]) + if (myXPLDevices[i] && myXPLDevices[i]->RefsLoaded) myXPLDevices[i]->_writePacket(XPLREQUEST_REFRESH, ""); + } + +} + +void sendExitMessage(void) +{ + fprintf(errlog, "\n*Xplane indicates that it is closing or unloading the current aircraft. I am letting all the devices know.\n"); + + for (int i = 0; i < XPLDEVICES_MAXDEVICES; i++) + { + if (myXPLDevices[i]) + if (myXPLDevices[i] && myXPLDevices[i]->RefsLoaded) myXPLDevices[i]->_writePacket(XPL_EXITING, ""); + } + +} + + + +/* +* reloadDevices +*/ +void reloadDevices(void) +{ + fprintf(errlog, "XPLPro device requested to reset and reload devices. \n"); + + + disengageDevices(); // just to make sure we are cleared + engageDevices(); + + + +} + + +/* + * map functions + */ +float mapFloat(long x, long inMin, long inMax, long outMin, long outMax) +{ + return (float)(x - inMin) * (outMax - outMin) / (float)(inMax - inMin) + outMin; +} + +long mapInt(long x, long inMin, long inMax, long outMin, long outMax) +{ + return (x - inMin) * (outMax - outMin) / (inMax - inMin) + outMin; +} \ No newline at end of file diff --git a/XPLPro_Plugin_Source/DataTransfer.h b/XPLPro_Plugin_Source/DataTransfer.h new file mode 100644 index 0000000..48ba07b --- /dev/null +++ b/XPLPro_Plugin_Source/DataTransfer.h @@ -0,0 +1,69 @@ +#pragma once +//#include "Serial.h" +#include "XPLProCommon.h" + +void BindingsSetup(void); +void BindingsLoad(void); + +int findDevices(void); +void activateDevices(void); +void sendExitMessage(void); +void sendRefreshRequest(void); +void disengageDevices(void); +void engageDevices(void); +void _processPacket(int); +void _processSerial(void); +void _updateDataRefs(int forceUpdate); +void _updateCommands(void); +int _writePacket(int port, char, char*); +int _writePacketN(int port, char, char*, int); +void reloadDevices(void); + +float mapFloat(long x, long inMin, long inMax, long outMin, long outMax); +long mapInt(long x, long inMin, long inMax, long outMin, long outMax); + +struct DataRefBinding +{ + int deviceIndex; // which XPLDirectDevice is this attached to + int bindingActive; // Is this binding being used + int Handle; // Handle is arbitrary and incremental and assigned by this plugin to send to arduino board +// int RWMode; // XPL_READ 1 XPL_WRITE 2 XPL_READWRITE 3 + int readFlag[XPLMAX_ELEMENTS]; // true if device requests updates for this dataref value/element + float precision; // reduce resolution by dividing then remultiplying with this number, or 0 for no processing + int updateRate; // minimum time in ms between updates sent + time_t lastUpdate; // time of last update + XPLMDataRef xplaneDataRefHandle; // Dataref handle of xplane element associated with binding + XPLMDataTypeID xplaneDataRefTypeID; // dataRef type + char xplaneDataRefName[80]; // character name of xplane dataref + int scaleFlag; + int scaleFromLow; + int scaleFromHigh; + int scaleToLow; + int scaleToHigh; + int currentElementSent[XPLMAX_ELEMENTS]; + long currentSentl[XPLMAX_ELEMENTS]; // Current long value sent to device + long currentReceivedl[XPLMAX_ELEMENTS]; // Current long value sent to Xplane + float currentSentf[XPLMAX_ELEMENTS]; // Current float value sent to device + + float currentReceivedf[XPLMAX_ELEMENTS]; // Current float value sent to Xplane + double currentSentD[XPLMAX_ELEMENTS]; // current double value sent to device + double currentReceivedD[XPLMAX_ELEMENTS]; // current double value sent to Xplane + + char* currentSents[XPLMAX_ELEMENTS]; // dynamically allocated string buffer for string types. + + +}; + +struct CommandBinding +{ + int deviceIndex; // which XPL Device is this attached to + int bindingActive; // Is this binding being used + int Handle; // Handle is incremental and assigned by this plugin to send to arduino board + + XPLMCommandRef xplaneCommandHandle; // Dataref handle of xplane element associated with binding + + char xplaneCommandName[80]; // character name of xplane dataref + int accumulator; + //int xplaneCurrentReceived; // Current value sent to Xplane + +}; diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPStandardWidgets.h b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPStandardWidgets.h new file mode 100644 index 0000000..42d4987 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPStandardWidgets.h @@ -0,0 +1,556 @@ +#ifndef _XPStandardWidgets_h_ +#define _XPStandardWidgets_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPStandardWidgets + ***************************************************************************/ +/* + * ## THEORY OF OPERATION + * + * The standard widgets are widgets built into the widgets library. While you + * can gain access to the widget function that drives them, you generally use + * them by calling XPCreateWidget and then listening for special messages, + * etc. + * + * The standard widgets often send mesages to themselves when the user + * performs an event; these messages are sent up the widget hierarchy until + * they are handled. So you can add a widget proc directly to a push button + * (for example) to intercept the message when it is clicked, or you can put + * one widget proc on a window for all of the push buttons in the window. Most + * of these messages contain the original widget ID as a parameter so you can + * know which widget is messaging no matter who it is sent to. + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * MAIN WINDOW + ***************************************************************************/ +/* + * The main window widget class provides a "window" as the user knows it. + * These windows are dragable and can be selected. Use them to create floating + * windows and non-modal dialogs. + * + */ + + +#define xpWidgetClass_MainWindow 1 + +/* + * Main Window Type Values + * + * These type values are used to control the appearance of a main window. + * + */ +enum { + /* The standard main window; pin stripes on XP7, metal frame on XP 6. */ + xpMainWindowStyle_MainWindow = 0, + + /* A translucent dark gray window, like the one ATC messages appear in. */ + xpMainWindowStyle_Translucent = 1, + + +}; + +/* + * Main Window Properties + * + */ +enum { + /* This property specifies the type of window. Set to one of the main window * + * types above. */ + xpProperty_MainWindowType = 1100, + + /* This property specifies whether the main window has close boxes in its * + * corners. */ + xpProperty_MainWindowHasCloseBoxes = 1200, + + +}; + +/* + * MainWindow Messages + * + */ +enum { + /* This message is sent when the close buttons are pressed for your window. */ + xpMessage_CloseButtonPushed = 1200, + + +}; + +/*************************************************************************** + * SUB WINDOW + ***************************************************************************/ +/* + * X-Plane dialogs are divided into separate areas; the sub window widgets + * allow you to make these areas. Create one main window and place several + * subwindows inside it. Then place your controls inside the subwindows. + * + */ + + +#define xpWidgetClass_SubWindow 2 + +/* + * SubWindow Type Values + * + * These values control the appearance of the subwindow. + * + */ +enum { + /* A panel that sits inside a main window. */ + xpSubWindowStyle_SubWindow = 0, + + /* A screen that sits inside a panel for showing text information. */ + xpSubWindowStyle_Screen = 2, + + /* A list view for scrolling lists. */ + xpSubWindowStyle_ListView = 3, + + +}; + +/* + * SubWindow Properties + * + */ +enum { + /* This property specifies the type of window. Set to one of the subwindow * + * types above. */ + xpProperty_SubWindowType = 1200, + + +}; + +/*************************************************************************** + * BUTTON + ***************************************************************************/ +/* + * The button class provides a number of different button styles and + * behaviors, including push buttons, radio buttons, check boxes, etc. The + * button label appears on or next to the button depending on the button's + * appearance, or type. + * + * The button's behavior is a separate property that dictates who it hilights + * and what kinds of messages it sends. Since behavior and type are different, + * you can do strange things like make check boxes that act as push buttons or + * push buttons with radio button behavior. + * + * In X-Plane 6 there were no check box graphics. The result is the following + * behavior: in X-Plane + * 6 all check box and radio buttons are round (radio-button style) buttons; + * in X-Plane 7 they are all square (check-box style) buttons. In a future + * version of X-Plane, the xpButtonBehavior enums will provide the correct + * graphic (check box or radio button) giving the expected result. + * + */ + + +#define xpWidgetClass_Button 3 + +/* + * Button Types + * + * These define the visual appearance of buttons but not how they respond to + * the mouse. + * + */ +enum { + /* This is a standard push button, like an 'OK' or 'Cancel' button in a dialog* + * box. */ + xpPushButton = 0, + + /* A check box or radio button. Use this and the button behaviors below to * + * get the desired behavior. */ + xpRadioButton = 1, + + /* A window close box. */ + xpWindowCloseBox = 3, + + /* A small down arrow. */ + xpLittleDownArrow = 5, + + /* A small up arrow. */ + xpLittleUpArrow = 6, + + +}; + +/* + * Button Behavior Values + * + * These define how the button responds to mouse clicks. + * + */ +enum { + /* Standard push button behavior. The button hilites while the mouse is * + * clicked over it and unhilites when the mouse is moved outside of it or * + * released. If the mouse is released over the button, the * + * xpMsg_PushButtonPressed message is sent. */ + xpButtonBehaviorPushButton = 0, + + /* Check box behavior. The button immediately toggles its value when the mouse* + * is clicked and sends out a xpMsg_ButtonStateChanged message. */ + xpButtonBehaviorCheckBox = 1, + + /* Radio button behavior. The button immediately sets its state to one and * + * sends out a xpMsg_ButtonStateChanged message if it was not already set to * + * one. You must turn off other radio buttons in a group in your code. */ + xpButtonBehaviorRadioButton = 2, + + +}; + +/* + * Button Properties + * + */ +enum { + /* This property sets the visual type of button. Use one of the button types * + * above. */ + xpProperty_ButtonType = 1300, + + /* This property sets the button's behavior. Use one of the button behaviors * + * above. */ + xpProperty_ButtonBehavior = 1301, + + /* This property tells whether a check box or radio button is "checked" or * + * not. Not used for push buttons. */ + xpProperty_ButtonState = 1302, + + +}; + +/* + * Button Messages + * + * These messages are sent by the button to itself and then up the widget + * chain when the button is clicked. (You may intercept them by providing a + * widget handler for the button itself or by providing a handler in a parent + * widget.) + * + */ +enum { + /* This message is sent when the user completes a click and release in a * + * button with push button behavior. Parameter one of the message is the * + * widget ID of the button. This message is dispatched up the widget * + * hierarchy. */ + xpMsg_PushButtonPressed = 1300, + + /* This message is sent when a button is clicked that has radio button or * + * check box behavior and its value changes. (Note that if the value changes * + * by setting a property you do not receive this message!) Parameter one is * + * the widget ID of the button, parameter 2 is the new state value, either * + * zero or one. This message is dispatched up the widget hierarchy. */ + xpMsg_ButtonStateChanged = 1301, + + +}; + +/*************************************************************************** + * TEXT FIELD + ***************************************************************************/ +/* + * The text field widget provides an editable text field including mouse + * selection and keyboard navigation. The contents of the text field are its + * descriptor. (The descriptor changes as the user types.) + * + * The text field can have a number of types, that effect the visual layout of + * the text field. The text field sends messages to itself so you may control + * its behavior. + * + * If you need to filter keystrokes, add a new handler and intercept the key + * press message. Since key presses are passed by pointer, you can modify the + * keystroke and pass it through to the text field widget. + * + * WARNING: in X-Plane before 7.10 (including 6.70) null characters could + * crash X-Plane. To prevent this, wrap this object with a filter function + * (more instructions can be found on the SDK website). + * + */ + + +#define xpWidgetClass_TextField 4 + +/* + * Text Field Type Values + * + * These control the look of the text field. + * + */ +enum { + /* A field for text entry. */ + xpTextEntryField = 0, + + /* A transparent text field. The user can type and the text is drawn, but no * + * background is drawn. You can draw your own background by adding a widget * + * handler and prehandling the draw message. */ + xpTextTransparent = 3, + + /* A translucent edit field, dark gray. */ + xpTextTranslucent = 4, + + +}; + +/* + * Text Field Properties + * + */ +enum { + /* This is the character position the selection starts at, zero based. If it * + * is the same as the end insertion point, the insertion point is not a * + * selection. */ + xpProperty_EditFieldSelStart = 1400, + + /* This is the character position of the end of the selection. */ + xpProperty_EditFieldSelEnd = 1401, + + /* This is the character position a drag was started at if the user is * + * dragging to select text, or -1 if a drag is not in progress. */ + xpProperty_EditFieldSelDragStart = 1402, + + /* This is the type of text field to display, from the above list. */ + xpProperty_TextFieldType = 1403, + + /* Set this property to 1 to password protect the field. Characters will be * + * drawn as *s even though the descriptor will contain plain-text. */ + xpProperty_PasswordMode = 1404, + + /* The max number of characters you can enter, if limited. Zero means * + * unlimited. */ + xpProperty_MaxCharacters = 1405, + + /* The first visible character on the left. This effectively scrolls the text* + * field. */ + xpProperty_ScrollPosition = 1406, + + /* The font to draw the field's text with. (An XPLMFontID.) */ + xpProperty_Font = 1407, + + /* This is the active side of the insert selection. (Internal) */ + xpProperty_ActiveEditSide = 1408, + + +}; + +/* + * Text Field Messages + * + */ +enum { + /* The text field sends this message to itself when its text changes. It sends* + * the message up the call chain; param1 is the text field's widget ID. */ + xpMsg_TextFieldChanged = 1400, + + +}; + +/*************************************************************************** + * SCROLL BAR + ***************************************************************************/ +/* + * A standard scroll bar or slider control. The scroll bar has a minimum, + * maximum and current value that is updated when the user drags it. The + * scroll bar sends continuous messages as it is dragged. + * + */ + + +#define xpWidgetClass_ScrollBar 5 + +/* + * Scroll Bar Type Values + * + * This defines how the scroll bar looks. + * + */ +enum { + /* A standard X-Plane scroll bar (with arrows on the ends). */ + xpScrollBarTypeScrollBar = 0, + + /* A slider, no arrows. */ + xpScrollBarTypeSlider = 1, + + +}; + +/* + * Scroll Bar Properties + * + */ +enum { + /* The current position of the thumb (in between the min and max, inclusive) */ + xpProperty_ScrollBarSliderPosition = 1500, + + /* The value the scroll bar has when the thumb is in the lowest position. */ + xpProperty_ScrollBarMin = 1501, + + /* The value the scroll bar has when the thumb is in the highest position. */ + xpProperty_ScrollBarMax = 1502, + + /* How many units to move the scroll bar when clicking next to the thumb. The * + * scroll bar always moves one unit when the arrows are clicked. */ + xpProperty_ScrollBarPageAmount = 1503, + + /* The type of scrollbar from the enums above. */ + xpProperty_ScrollBarType = 1504, + + /* Used internally. */ + xpProperty_ScrollBarSlop = 1505, + + +}; + +/* + * Scroll Bar Messages + * + */ +enum { + /* The scroll bar sends this message when the slider position changes. It * + * sends the message up the call chain; param1 is the Scroll Bar widget ID. */ + xpMsg_ScrollBarSliderPositionChanged = 1500, + + +}; + +/*************************************************************************** + * CAPTION + ***************************************************************************/ +/* + * A caption is a simple widget that shows its descriptor as a string, useful + * for labeling parts of a window. It always shows its descriptor as its + * string and is otherwise transparent. + * + */ + + +#define xpWidgetClass_Caption 6 + +/* + * Caption Properties + * + */ +enum { + /* This property specifies whether the caption is lit; use lit captions * + * against screens. */ + xpProperty_CaptionLit = 1600, + + +}; + +/*************************************************************************** + * GENERAL GRAPHICS + ***************************************************************************/ +/* + * The general graphics widget can show one of many icons available from + * X-Plane. + * + */ + + +#define xpWidgetClass_GeneralGraphics 7 + +/* + * General Graphics Types Values + * + * These define the icon for the general graphics. + * + */ +enum { + xpShip = 4, + + xpILSGlideScope = 5, + + xpMarkerLeft = 6, + + xp_Airport = 7, + + xpNDB = 8, + + xpVOR = 9, + + xpRadioTower = 10, + + xpAircraftCarrier = 11, + + xpFire = 12, + + xpMarkerRight = 13, + + xpCustomObject = 14, + + xpCoolingTower = 15, + + xpSmokeStack = 16, + + xpBuilding = 17, + + xpPowerLine = 18, + + xpVORWithCompassRose = 19, + + xpOilPlatform = 21, + + xpOilPlatformSmall = 22, + + xpWayPoint = 23, + + +}; + +/* + * General Graphics Properties + * + */ +enum { + /* This property controls the type of icon that is drawn. */ + xpProperty_GeneralGraphicsType = 1700, + + +}; + +/*************************************************************************** + * PROGRESS INDICATOR + ***************************************************************************/ +/* + * This widget implements a progress indicator as seen when X-Plane starts up. + * + */ + +#define xpWidgetClass_Progress 8 + +/* + * Progress Indicator Properties + * + */ +enum { + /* This is the current value of the progress indicator. */ + xpProperty_ProgressPosition = 1800, + + /* This is the minimum value, equivalent to 0% filled. */ + xpProperty_ProgressMin = 1801, + + /* This is the maximum value, equivalent to 100% filled. */ + xpProperty_ProgressMax = 1802, + + +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPUIGraphics.h b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPUIGraphics.h new file mode 100644 index 0000000..b70e0f6 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPUIGraphics.h @@ -0,0 +1,354 @@ +#ifndef _XPUIGraphics_h_ +#define _XPUIGraphics_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPUIGraphics + ***************************************************************************/ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * UI GRAPHICS + ***************************************************************************/ + +/* + * XPWindowStyle + * + * There are a few built-in window styles in X-Plane that you can use. + * + * Note that X-Plane 6 does not offer real shadow-compositing; you must make + * sure to put a window on top of another window of the right style to the + * shadows work, etc. This applies to elements with insets and shadows. The + * rules are: + * + * Sub windows must go on top of main windows, and screens and list views on + * top of subwindows. Only help and main windows can be over the main screen. + * + * With X-Plane 7 any window or element may be placed over any other element. + * + * Some windows are scaled by stretching, some by repeating. The drawing + * routines know which scaling method to use. The list view cannot be rescaled + * in X-Plane 6 because it has both a repeating pattern and a gradient in one + * element. All other elements can be rescaled. + * + */ +enum { + /* An LCD screen that shows help. */ + xpWindow_Help = 0, + + /* A dialog box window. */ + xpWindow_MainWindow = 1, + + /* A panel or frame within a dialog box window. */ + xpWindow_SubWindow = 2, + + /* An LCD screen within a panel to hold text displays. */ + xpWindow_Screen = 4, + + /* A list view within a panel for scrolling file names, etc. */ + xpWindow_ListView = 5, + + +}; +typedef int XPWindowStyle; + +/* + * XPDrawWindow + * + * This routine draws a window of the given dimensions at the given offset on + * the virtual screen in a given style. The window is automatically scaled as + * appropriate using a bitmap scaling technique (scaling or repeating) as + * appropriate to the style. + * + */ +WIDGET_API void XPDrawWindow( + int inX1, + int inY1, + int inX2, + int inY2, + XPWindowStyle inStyle); + +/* + * XPGetWindowDefaultDimensions + * + * This routine returns the default dimensions for a window. Output is either + * a minimum or fixed value depending on whether the window is scalable. + * + */ +WIDGET_API void XPGetWindowDefaultDimensions( + XPWindowStyle inStyle, + int * outWidth, /* Can be NULL */ + int * outHeight); /* Can be NULL */ + +/* + * XPElementStyle + * + * Elements are individually drawable UI things like push buttons, etc. The + * style defines what kind of element you are drawing. Elements can be + * stretched in one or two dimensions (depending on the element). Some + * elements can be lit. + * + * In X-Plane 6 some elements must be drawn over metal. Some are scalable and + * some are not. Any element can be drawn anywhere in X-Plane 7. + * + * Scalable Axis Required Background + * + */ +enum { + /* x metal */ + xpElement_TextField = 6, + + /* none metal */ + xpElement_CheckBox = 9, + + /* none metal */ + xpElement_CheckBoxLit = 10, + + /* none window header */ + xpElement_WindowCloseBox = 14, + + /* none window header */ + xpElement_WindowCloseBoxPressed = 15, + + /* x metal */ + xpElement_PushButton = 16, + + /* x metal */ + xpElement_PushButtonLit = 17, + + /* none any */ + xpElement_OilPlatform = 24, + + /* none any */ + xpElement_OilPlatformSmall = 25, + + /* none any */ + xpElement_Ship = 26, + + /* none any */ + xpElement_ILSGlideScope = 27, + + /* none any */ + xpElement_MarkerLeft = 28, + + /* none any */ + xpElement_Airport = 29, + + /* none any */ + xpElement_Waypoint = 30, + + /* none any */ + xpElement_NDB = 31, + + /* none any */ + xpElement_VOR = 32, + + /* none any */ + xpElement_RadioTower = 33, + + /* none any */ + xpElement_AircraftCarrier = 34, + + /* none any */ + xpElement_Fire = 35, + + /* none any */ + xpElement_MarkerRight = 36, + + /* none any */ + xpElement_CustomObject = 37, + + /* none any */ + xpElement_CoolingTower = 38, + + /* none any */ + xpElement_SmokeStack = 39, + + /* none any */ + xpElement_Building = 40, + + /* none any */ + xpElement_PowerLine = 41, + + /* none metal */ + xpElement_CopyButtons = 45, + + /* none metal */ + xpElement_CopyButtonsWithEditingGrid = 46, + + /* x, y metal */ + xpElement_EditingGrid = 47, + + /* THIS CAN PROBABLY BE REMOVED */ + xpElement_ScrollBar = 48, + + /* none any */ + xpElement_VORWithCompassRose = 49, + + /* none metal */ + xpElement_Zoomer = 51, + + /* x, y metal */ + xpElement_TextFieldMiddle = 52, + + /* none metal */ + xpElement_LittleDownArrow = 53, + + /* none metal */ + xpElement_LittleUpArrow = 54, + + /* none metal */ + xpElement_WindowDragBar = 61, + + /* none metal */ + xpElement_WindowDragBarSmooth = 62, + + +}; +typedef int XPElementStyle; + +/* + * XPDrawElement + * + * XPDrawElement draws a given element at an offset on the virtual screen in + * set dimensions. + * *Even* if the element is not scalable, it will be scaled if the width and + * height do not match the preferred dimensions; it'll just look ugly. Pass + * inLit to see the lit version of the element; if the element cannot be lit + * this is ignored. + * + */ +WIDGET_API void XPDrawElement( + int inX1, + int inY1, + int inX2, + int inY2, + XPElementStyle inStyle, + int inLit); + +/* + * XPGetElementDefaultDimensions + * + * This routine returns the recommended or minimum dimensions of a given UI + * element. outCanBeLit tells whether the element has both a lit and unlit + * state. Pass `NULL` to not receive any of these parameters. + * + */ +WIDGET_API void XPGetElementDefaultDimensions( + XPElementStyle inStyle, + int * outWidth, /* Can be NULL */ + int * outHeight, /* Can be NULL */ + int * outCanBeLit); /* Can be NULL */ + +/* + * XPTrackStyle + * + * A track is a UI element that displays a value vertically or horizontally. + * X-Plane has three kinds of tracks: scroll bars, sliders, and progress bars. + * Tracks can be displayed either horizontally or vertically; tracks will + * choose their own layout based on the larger dimension of their dimensions + * (e.g. they know if they are tall or wide). Sliders may be lit or unlit + * (showing the user manipulating them). + * + * - ScrollBar: this is a standard scroll bar with arrows and a thumb to drag. + * - Slider: this is a simple track with a ball in the middle that can be + * slid. + * - Progress: this is a progress indicator showing how a long task is going. + * + */ +enum { + /* not over metal can be lit can be rotated */ + xpTrack_ScrollBar = 0, + + /* over metal can be lit can be rotated */ + xpTrack_Slider = 1, + + /* over metal cannot be lit cannot be rotated */ + xpTrack_Progress = 2, + + +}; +typedef int XPTrackStyle; + +/* + * XPDrawTrack + * + * This routine draws a track. You pass in the track dimensions and size; the + * track picks the optimal orientation for these dimensions. Pass in the + * track's minimum current and maximum values; the indicator will be + * positioned appropriately. You can also specify whether the track is lit or + * not. + * + */ +WIDGET_API void XPDrawTrack( + int inX1, + int inY1, + int inX2, + int inY2, + int inMin, + int inMax, + int inValue, + XPTrackStyle inTrackStyle, + int inLit); + +/* + * XPGetTrackDefaultDimensions + * + * This routine returns a track's default smaller dimension; all tracks are + * scalable in the larger dimension. It also returns whether a track can be + * lit. + * + */ +WIDGET_API void XPGetTrackDefaultDimensions( + XPTrackStyle inStyle, + int * outWidth, + int * outCanBeLit); + +/* + * XPGetTrackMetrics + * + * This routine returns the metrics of a track. If you want to write UI code + * to manipulate a track, this routine helps you know where the mouse + * locations are. For most other elements, the rectangle the element is drawn + * in is enough information. However, the scrollbar drawing routine does some + * automatic placement; this routine lets you know where things ended up. You + * pass almost everything you would pass to the draw routine. You get out the + * orientation, and other useful stuff. + * + * Besides orientation, you get five dimensions for the five parts of a + * scrollbar, which are the down button, down area (area before the thumb), + * the thumb, and the up area and button. For horizontal scrollers, the left + * button decreases; for vertical scrollers, the top button decreases. + * + */ +WIDGET_API void XPGetTrackMetrics( + int inX1, + int inY1, + int inX2, + int inY2, + int inMin, + int inMax, + int inValue, + XPTrackStyle inTrackStyle, + int * outIsVertical, + int * outDownBtnSize, + int * outDownPageSize, + int * outThumbSize, + int * outUpPageSize, + int * outUpBtnSize); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgetDefs.h b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgetDefs.h new file mode 100644 index 0000000..c1b2341 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgetDefs.h @@ -0,0 +1,472 @@ +#ifndef _XPWidgetDefs_h_ +#define _XPWidgetDefs_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPWidgetDefs + ***************************************************************************/ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if APL + #if XPWIDGETS + #if __GNUC__ >= 4 + #define WIDGET_API __attribute__((visibility("default"))) + #elif __MACH__ + #define WIDGET_API + #else + #define WIDGET_API __declspec(dllexport) + #endif + #else + #define WIDGET_API + #endif +#elif IBM + #if XPWIDGETS + #define WIDGET_API __declspec(dllexport) + #else + #define WIDGET_API __declspec(dllimport) + #endif +#elif LIN + #if XPWIDGETS + #if __GNUC__ >= 4 + #define WIDGET_API __attribute__((visibility("default"))) + #else + #define WIDGET_API + #endif + #else + #define WIDGET_API + #endif +#else +#pragma error "Platform not defined!" +#endif + /*************************************************************************** + * WIDGET DEFINITIONS + ***************************************************************************/ +/* + * A widget is a call-back driven screen entity like a push-button, window, + * text entry field, etc. + * + * Use the widget API to create widgets of various classes. You can nest them + * into trees of widgets to create complex user interfaces. + * + */ + + +/* + * XPWidgetID + * + * A Widget ID is an opaque unique non-zero handle identifying your widget. + * Use 0 to specify "no widget". This type is defined as wide enough to hold a + * pointer. You receive a widget ID when you create a new widget and then use + * that widget ID to further refer to the widget. + * + */ +typedef void * XPWidgetID; + +/* + * XPWidgetPropertyID + * + * Properties are values attached to instances of your widgets. A property is + * identified by a 32-bit ID and its value is the width of a pointer. + * + * Each widget instance may have a property or not have it. When you set a + * property on a widget for the first time, the property is added to the + * widget; it then stays there for the life of the widget. + * + * Some property IDs are predefined by the widget package; you can make up + * your own property IDs as well. + * + */ +enum { + /* A window's refcon is an opaque value used by client code to find other data* + * based on it. */ + xpProperty_Refcon = 0, + + /* These properties are used by the utlities to implement dragging. */ + xpProperty_Dragging = 1, + + xpProperty_DragXOff = 2, + + xpProperty_DragYOff = 3, + + /* Is the widget hilited? (For widgets that support this kind of thing.) */ + xpProperty_Hilited = 4, + + /* Is there a C++ object attached to this widget? */ + xpProperty_Object = 5, + + /* If this property is 1, the widget package will use OpenGL to restrict * + * drawing to the Wiget's exposed rectangle. */ + xpProperty_Clip = 6, + + /* Is this widget enabled (for those that have a disabled state too)? */ + xpProperty_Enabled = 7, + + /* NOTE: Property IDs 1 - 999 are reserved for the widgets library. * + * * + * NOTE: Property IDs 1000 - 9999 are allocated to the standard widget classes* + * provided with the library. * + * * + * Properties 1000 - 1099 are for widget class 0, 1100 - 1199 for widget class* + * 1, etc. */ + xpProperty_UserStart = 10000, + + +}; +typedef int XPWidgetPropertyID; + +/* + * XPMouseState_t + * + * When the mouse is clicked or dragged, a pointer to this structure is passed + * to your widget function. + * + */ +typedef struct { + int x; + int y; + /* Mouse Button number, left = 0 (right button not yet supported. */ + int button; +#if defined(XPLM200) + /* Scroll wheel delta (button in this case would be the wheel axis number). */ + int delta; +#endif /* XPLM200 */ +} XPMouseState_t; + +/* + * XPKeyState_t + * + * When a key is pressed, a pointer to this struct is passed to your widget + * function. + * + */ +typedef struct { + /* The ASCII key that was pressed. WARNING: this may be 0 for some non-ASCII * + * key sequences. */ + char key; + /* The flags. Make sure to check this if you only want key-downs! */ + XPLMKeyFlags flags; + /* The virtual key code for the key */ + char vkey; +} XPKeyState_t; + +/* + * XPWidgetGeometryChange_t + * + * This structure contains the deltas for your widget's geometry when it + * changes. + * + */ +typedef struct { + int dx; + /* +Y = the widget moved up */ + int dy; + int dwidth; + int dheight; +} XPWidgetGeometryChange_t; + +/* + * XPDispatchMode + * + * The dispatching modes describe how the widgets library sends out messages. + * Currently there are three modes: + * + */ +enum { + /* The message will only be sent to the target widget. */ + xpMode_Direct = 0, + + /* The message is sent to the target widget, then up the chain of parents * + * until the message is handled or a parentless widget is reached. */ + xpMode_UpChain = 1, + + /* The message is sent to the target widget and then all of its children * + * recursively depth-first. */ + xpMode_Recursive = 2, + + /* The message is snet just to the target, but goes to every callback, even if* + * it is handled. */ + xpMode_DirectAllCallbacks = 3, + + /* The message is only sent to the very first handler even if it is not * + * accepted. (This is really only useful for some internal widget library * + * functions.) */ + xpMode_Once = 4, + + +}; +typedef int XPDispatchMode; + +/* + * XPWidgetClass + * + * Widget classes define predefined widget types. A widget class basically + * specifies from a library the widget function to be used for the widget. + * Most widgets can be made right from classes. + * + */ +typedef int XPWidgetClass; + +/* An unspecified widget class. Other widget classes are in * + * XPStandardWidgets.h */ +#define xpWidgetClass_None 0 + +/*************************************************************************** + * WIDGET MESSAGES + ***************************************************************************/ + +/* + * XPWidgetMessage + * + * Widgets receive 32-bit messages indicating what action is to be taken or + * notifications of events. The list of messages may be expanded. + * + */ +enum { + /* No message, should not be sent. */ + xpMsg_None = 0, + + /* The create message is sent once per widget that is created with your widget* + * function and once for any widget that has your widget function attached. * + * * + * Dispatching: Direct * + * * + * Param 1: 1 if you are being added as a subclass, 0 if the widget is first * + * being created. */ + xpMsg_Create = 1, + + /* The destroy message is sent once for each message that is destroyed that * + * has your widget function. * + * * + * Dispatching: Direct for all * + * * + * Param 1: 1 if being deleted by a recursive delete to the parent, 0 for * + * explicit deletion. */ + xpMsg_Destroy = 2, + + /* The paint message is sent to your widget to draw itself. The paint message * + * is the bare-bones message; in response you must draw yourself, draw your * + * children, set up clipping and culling, check for visibility, etc. If you * + * don't want to do all of this, ignore the paint message and a draw message * + * (see below) will be sent to you. * + * * + * Dispatching: Direct */ + xpMsg_Paint = 3, + + /* The draw message is sent to your widget when it is time to draw yourself. * + * OpenGL will be set up to draw in 2-d global screen coordinates, but you * + * should use the XPLM to set up OpenGL state. * + * * + * Dispatching: Direct */ + xpMsg_Draw = 4, + + /* The key press message is sent once per key that is pressed. The first * + * parameter is the type of key code (integer or char) and the second is the * + * code itself. By handling this event, you consume the key stroke. * + * * + * Handling this message 'consumes' the keystroke; not handling it passes it * + * to your parent widget. * + * * + * Dispatching: Up Chain * + * * + * Param 1: A pointer to an XPKeyState_t structure with the keystroke. */ + xpMsg_KeyPress = 5, + + /* Keyboard focus is being given to you. By handling this message you accept * + * keyboard focus. The first parameter will be one if a child of yours gave up* + * focus to you, 0 if someone set focus on you explicitly. * + * * + * Handling this message accepts focus; not handling refuses focus. * + * * + * Dispatching: direct * + * * + * Param 1: 1 if you are gaining focus because your child is giving it up, 0 * + * if someone is explicitly giving you focus. */ + xpMsg_KeyTakeFocus = 6, + + /* Keyboard focus is being taken away from you. The first parameter will be * + * one if you are losing focus because another widget is taking it, or 0 if * + * someone called the API to make you lose focus explicitly. * + * * + * Dispatching: Direct * + * * + * Param 1: 1 if focus is being taken by another widget, 0 if code requested * + * to remove focus. */ + xpMsg_KeyLoseFocus = 7, + + /* You receive one mousedown event per click with a mouse-state structure * + * pointed to by parameter 1, by accepting this you eat the click, otherwise * + * your parent gets it. You will not receive drag and mouse up messages if you* + * do not accept the down message. * + * * + * Handling this message consumes the mouse click, not handling it passes it * + * to the next widget. You can act 'transparent' as a window by never handling* + * moues clicks to certain areas. * + * * + * Dispatching: Up chain NOTE: Technically this is direct dispatched, but the * + * widgets library will shop it to each widget until one consumes the click, * + * making it effectively "up chain". * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseDown = 8, + + /* You receive a series of mouse drag messages (typically one per frame in the* + * sim) as the mouse is moved once you have accepted a mouse down message. * + * Parameter one points to a mouse-state structure describing the mouse * + * location. You will continue to receive these until the mouse button is * + * released. You may receive multiple mouse state messages with the same mouse* + * position. You will receive mouse drag events even if the mouse is dragged * + * out of your current or original bounds at the time of the mouse down. * + * * + * Dispatching: Direct * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseDrag = 9, + + /* The mouseup event is sent once when the mouse button is released after a * + * drag or click. You only receive this message if you accept the mouseDown * + * message. Parameter one points to a mouse state structure. * + * * + * Dispatching: Direct * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseUp = 10, + + /* Your geometry or a child's geometry is being changed. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the original reshaped target. * + * * + * Param 2: A pointer to a XPWidgetGeometryChange_t struct describing the * + * change. */ + xpMsg_Reshape = 11, + + /* Your exposed area has changed. * + * * + * Dispatching: Direct */ + xpMsg_ExposedChanged = 12, + + /* A child has been added to you. The child's ID is passed in parameter one. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of the child being added. */ + xpMsg_AcceptChild = 13, + + /* A child has been removed from to you. The child's ID is passed in parameter* + * one. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of the child being removed. */ + xpMsg_LoseChild = 14, + + /* You now have a new parent, or have no parent. The parent's ID is passed in,* + * or 0 for no parent. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of your parent */ + xpMsg_AcceptParent = 15, + + /* You or a child has been shown. Note that this does not include you being * + * shown because your parent was shown, you were put in a new parent, your * + * root was shown, etc. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the shown widget. */ + xpMsg_Shown = 16, + + /* You have been hidden. See limitations above. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the hidden widget. */ + xpMsg_Hidden = 17, + + /* Your descriptor has changed. * + * * + * Dispatching: Direct */ + xpMsg_DescriptorChanged = 18, + + /* A property has changed. Param 1 contains the property ID. * + * * + * Dispatching: Direct * + * * + * Param 1: The Property ID being changed. * + * * + * Param 2: The new property value */ + xpMsg_PropertyChanged = 19, + +#if defined(XPLM200) + /* The mouse wheel has moved. * + * * + * Return 1 to consume the mouse wheel move, or 0 to pass the message to a * + * parent. Dispatching: Up chain * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseWheel = 20, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* The cursor is over your widget. If you consume this message, change the * + * XPLMCursorStatus value to indicate the desired result, with the same rules * + * as in XPLMDisplay.h. * + * * + * Return 1 to consume this message, 0 to pass it on. * + * * + * Dispatching: Up chain Param 1: A pointer to an XPMouseState_t struct * + * containing the mouse status. * + * * + * Param 2: A pointer to a XPLMCursorStatus - set this to the cursor result * + * you desire. */ + xpMsg_CursorAdjust = 21, + +#endif /* XPLM200 */ + /* NOTE: Message IDs 1000 - 9999 are allocated to the standard widget classes * + * provided with the library with 1000 - 1099 for widget class 0, 1100 - 1199 * + * for widget class 1, etc. Message IDs 10,000 and beyond are for plugin use. */ + xpMsg_UserStart = 10000, + + +}; +typedef int XPWidgetMessage; + +/*************************************************************************** + * WIDGET CALLBACK FUNCTION + ***************************************************************************/ + +/* + * XPWidgetFunc_t + * + * This function defines your custom widget's behavior. It will be called by + * the widgets library to send messages to your widget. The message and widget + * ID are passed in, as well as two ptr-width signed parameters whose meaning + * varies with the message. Return 1 to indicate that you have processed the + * message, 0 to indicate that you have not. For any message that is not + * understood, return 0. + * + */ +typedef int (* XPWidgetFunc_t)( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgetUtils.h b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgetUtils.h new file mode 100644 index 0000000..ff757f7 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgetUtils.h @@ -0,0 +1,232 @@ +#ifndef _XPWidgetUtils_h_ +#define _XPWidgetUtils_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPWidgetUtils + ***************************************************************************/ +/* + * ## USAGE NOTES + * + * The XPWidgetUtils library contains useful functions that make writing and + * using widgets less of a pain. + * + * One set of functions are the widget behavior functions. These functions + * each add specific useful behaviors to widgets. They can be used in two + * manners: + * + * 1. You can add a widget behavior function to a widget as a callback proc + * using the XPAddWidgetCallback function. The widget will gain that + * behavior. Remember that the last function you add has highest priority. + * You can use this to change or augment the behavior of an existing + * finished widget. + * 2. You can call a widget function from inside your own widget function. + * This allows you to include useful behaviors in custom-built widgets. A + * number of the standard widgets get their behavior from this library. To + * do this, call the behavior function from your function first. If it + * returns 1, that means it handled the event and you don't need to; simply + * return 1. + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * GENERAL UTILITIES + ***************************************************************************/ + + + +/* + * Convenience accessors + * + * It can be clumsy accessing the variables passed in by pointer to a struct + * for mouse and reshape messages; these accessors let you simply pass in the param + * right from the arguments of your widget proc and get back the value you want. + * + */ +#define MOUSE_X(param) (((XPMouseState_t *) (param))->x) +#define MOUSE_Y(param) (((XPMouseState_t *) (param))->y) + +#define DELTA_X(param) (((XPWidgetGeometryChange_t *) (param))->dx) +#define DELTA_Y(param) (((XPWidgetGeometryChange_t *) (param))->dy) +#define DELTA_W(param) (((XPWidgetGeometryChange_t *) (param))->dwidth) +#define DELTA_H(param) (((XPWidgetGeometryChange_t *) (param))->dheight) + +#define KEY_CHAR(param) (((XPKeyState_t *) (param))->key) +#define KEY_FLAGS(param) (((XPKeyState_t *) (param))->flags) +#define KEY_VKEY(param) (((XPKeyState_t *) (param))->vkey) + +#define IN_RECT(x, y, l, t, r, b) \ + (((x) >= (l)) && ((x) <= (r)) && ((y) >= (b)) && ((y) <= (t))) + +/* + * XPWidgetCreate_t + * + * This structure contains all of the parameters needed to create a wiget. It + * is used with XPUCreateWidgets to create widgets in bulk from an array. All + * parameters correspond to those of XPCreateWidget except for the container + * index. + * + * If the container index is equal to the index of a widget in the array, the + * widget in the array passed to XPUCreateWidgets is used as the parent of + * this widget. Note that if you pass an index greater than your own position + * in the array, the parent you are requesting will not exist yet. + * + * If the container index is NO_PARENT, the parent widget is specified as + * NULL. If the container index is PARAM_PARENT, the widget passed into + * XPUCreateWidgets is used. + * + */ +typedef struct { + int left; + int top; + int right; + int bottom; + int visible; + const char * descriptor; + /* Whether ethis widget is a root wiget */ + int isRoot; + /* The index of the widget to contain within, or a constant */ + int containerIndex; + XPWidgetClass widgetClass; +} XPWidgetCreate_t; + +#define NO_PARENT -1 + +#define PARAM_PARENT -2 + +#define WIDGET_COUNT(x) ((sizeof(x) / sizeof(XPWidgetCreate_t))) + +/* + * XPUCreateWidgets + * + * This function creates a series of widgets from a table (see + * XPCreateWidget_t above). Pass in an array of widget creation structures and + * an array of widget IDs that will receive each widget. + * + * Widget parents are specified by index into the created widget table, + * allowing you to create nested widget structures. You can create multiple + * widget trees in one table. Generally you should create widget trees from + * the top down. + * + * You can also pass in a widget ID that will be used when the widget's parent + * is listed as PARAM_PARENT; this allows you to embed widgets created with + * XPUCreateWidgets in a widget created previously. + * + */ +WIDGET_API void XPUCreateWidgets( + const XPWidgetCreate_t * inWidgetDefs, + int inCount, + XPWidgetID inParamParent, + XPWidgetID * ioWidgets); + +/* + * XPUMoveWidgetBy + * + * Simply moves a widget by an amount, +x = right, +y=up, without resizing the + * widget. + * + */ +WIDGET_API void XPUMoveWidgetBy( + XPWidgetID inWidget, + int inDeltaX, + int inDeltaY); + +/*************************************************************************** + * LAYOUT MANAGERS + ***************************************************************************/ +/* + * The layout managers are widget behavior functions for handling where + * widgets move. Layout managers can be called from a widget function or + * attached to a widget later. + * + */ + + +/* + * XPUFixedLayout + * + * This function causes the widget to maintain its children in fixed position + * relative to itself as it is resized. Use this on the top level 'window' + * widget for your window. + * + */ +WIDGET_API int XPUFixedLayout( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +/*************************************************************************** + * WIDGET PROC BEHAVIORS + ***************************************************************************/ +/* + * These widget behavior functions add other useful behaviors to widgets. + * These functions cannot be attached to a widget; they must be called from + * your widget function. + * + */ + + +/* + * XPUSelectIfNeeded + * + * This causes the widget to bring its window to the foreground if it is not + * already. inEatClick specifies whether clicks in the background should be + * consumed by bringin the window to the foreground. + * + */ +WIDGET_API int XPUSelectIfNeeded( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inEatClick); + +/* + * XPUDefocusKeyboard + * + * This causes a click in the widget to send keyboard focus back to X-Plane. + * This stops editing of any text fields, etc. + * + */ +WIDGET_API int XPUDefocusKeyboard( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inEatClick); + +/* + * XPUDragWidget + * + * XPUDragWidget drags the widget in response to mouse clicks. Pass in not + * only the event, but the global coordinates of the drag region, which might + * be a sub-region of your widget (for example, a title bar). + * + */ +WIDGET_API int XPUDragWidget( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inLeft, + int inTop, + int inRight, + int inBottom); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgets.h b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgets.h new file mode 100644 index 0000000..f4423e2 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Widgets/XPWidgets.h @@ -0,0 +1,538 @@ +#ifndef _XPWidgets_h_ +#define _XPWidgets_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPWidgets + ***************************************************************************/ +/* + * ## THEORY OF OPERATION AND NOTES + * + * Widgets are persistent view 'objects' for X-Plane. A widget is an object + * referenced by its opaque handle (widget ID) and the APIs in this file. You + * cannot access the widget's guts directly. Every Widget has the following + * intrinsic data: + * + * - A bounding box defined in global screen coordinates with 0,0 in the + * bottom left and +y = up, +x = right. + * - A visible box, which is the intersection of the bounding box with the + * widget's parents visible box. + * - Zero or one parent widgets. (Always zero if the widget is a root widget. + * - Zero or more child widgets. + * - Whether the widget is a root. Root widgets are the top level plugin + * windows. + * - Whether the widget is visible. + * - A text string descriptor, whose meaning varies from widget to widget. + * - An arbitrary set of 32 bit integral properties defined by 32-bit integral + * keys. This is how specific widgets store specific data. + * - A list of widget callbacks proc that implements the widgets behaviors. + * + * The Widgets library sends messages to widgets to request specific behaviors + * or notify the widget of things. + * + * Widgets may have more than one callback function, in which case messages + * are sent to the most recently added callback function until the message is + * handled. Messages may also be sent to parents or children; see the + * XPWidgetDefs.h header file for the different widget message dispatching + * functions. By adding a callback function to a window you can 'subclass' its + * behavior. + * + * A set of standard widgets are provided that serve common UI purposes. You + * can also customize or implement entirely custom widgets. + * + * Widgets are different than other view hierarchies (most notably Win32, + * which they bear a striking resemblance to) in the following ways: + * + * - Not all behavior can be patched. State that is managed by the XPWidgets + * DLL and not by individual widgets cannot be customized. + * - All coordinates are in global screen coordinates. Coordinates are not + * relative to an enclosing widget, nor are they relative to a display + * window. + * - Widget messages are always dispatched synchronously, and there is no + * concept of scheduling an update or a dirty region. Messages originate + * from X-Plane as the sim cycle goes by. Since X-Plane is constantly + * redrawing, so are widgets; there is no need to mark a part of a widget as + * 'needing redrawing' because redrawing happens frequently whether the + * widget needs it or not. + * - Any widget may be a 'root' widget, causing it to be drawn; there is no + * relationship between widget class and rootness. Root widgets are + * imlemented as XPLMDisply windows. + * + */ + +#include "XPWidgetDefs.h" +#include "XPLMDisplay.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * WIDGET CREATION AND MANAGEMENT + ***************************************************************************/ + +/* + * XPCreateWidget + * + * This function creates a new widget and returns the new widget's ID to you. + * If the widget creation fails for some reason, it returns NULL. Widget + * creation will fail either if you pass a bad class ID or if there is not + * adequate memory. + * + * Input Parameters: + * + * - Top, left, bottom, and right in global screen coordinates defining the + * widget's location on the screen. + * - inVisible is 1 if the widget should be drawn, 0 to start the widget as + * hidden. + * - inDescriptor is a null terminated string that will become the widget's + * descriptor. + * - inIsRoot is 1 if this is going to be a root widget, 0 if it will not be. + * - inContainer is the ID of this widget's container. It must be 0 for a root + * widget. for a non-root widget, pass the widget ID of the widget to place + * this widget within. If this widget is not going to start inside another + * widget, pass 0; this new widget will then just be floating off in space + * (and will not be drawn until it is placed in a widget. + * - inClass is the class of the widget to draw. Use one of the predefined + * class-IDs to create a standard widget. + * + * A note on widget embedding: a widget is only called (and will be drawn, + * etc.) if it is placed within a widget that will be called. Root widgets are + * always called. So it is possible to have whole chains of widgets that are + * simply not called. You can preconstruct widget trees and then place them + * into root widgets later to activate them if you wish. + * + */ +WIDGET_API XPWidgetID XPCreateWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inVisible, + const char * inDescriptor, + int inIsRoot, + XPWidgetID inContainer, + XPWidgetClass inClass); + +/* + * XPCreateCustomWidget + * + * This function is the same as XPCreateWidget except that instead of passing + * a class ID, you pass your widget callback function pointer defining the + * widget. Use this function to define a custom widget. All parameters are the + * same as XPCreateWidget, except that the widget class has been replaced with + * the widget function. + * + */ +WIDGET_API XPWidgetID XPCreateCustomWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inVisible, + const char * inDescriptor, + int inIsRoot, + XPWidgetID inContainer, + XPWidgetFunc_t inCallback); + +/* + * XPDestroyWidget + * + * This class destroys a widget. Pass in the ID of the widget to kill. If you + * pass 1 for inDestroyChilren, the widget's children will be destroyed first, + * then this widget will be destroyed. (Furthermore, the widget's children + * will be destroyed with the inDestroyChildren flag set to 1, so the + * destruction will recurse down the widget tree.) If you pass 0 for this + * flag, the child widgets will simply end up with their parent set to 0. + * + */ +WIDGET_API void XPDestroyWidget( + XPWidgetID inWidget, + int inDestroyChildren); + +/* + * XPSendMessageToWidget + * + * This sends any message to a widget. You should probably not go around + * simulating the predefined messages that the widgets library defines for + * you. You may however define custom messages for your widgets and send them + * with this method. + * + * This method supports several dispatching patterns; see XPDispatchMode for + * more info. The function returns 1 if the message was handled, 0 if it was + * not. + * + * For each widget that receives the message (see the dispatching modes), each + * widget function from the most recently installed to the oldest one receives + * the message in order until it is handled. + * + */ +WIDGET_API int XPSendMessageToWidget( + XPWidgetID inWidget, + XPWidgetMessage inMessage, + XPDispatchMode inMode, + intptr_t inParam1, + intptr_t inParam2); + +/*************************************************************************** + * WIDGET POSITIONING AND VISIBILITY + ***************************************************************************/ + +/* + * XPPlaceWidgetWithin + * + * This function changes which container a widget resides in. You may NOT use + * this function on a root widget! inSubWidget is the widget that will be + * moved. Pass a widget ID in inContainer to make inSubWidget be a child of + * inContainer. It will become the last/closest widget in the container. Pass + * 0 to remove the widget from any container. Any call to this other than + * passing the widget ID of the old parent of the affected widget will cause + * the widget to be removed from its old parent. Placing a widget within its + * own parent simply makes it the last widget. + * + * NOTE: this routine does not reposition the sub widget in global + * coordinates. If the container has layout management code, it will + * reposition the subwidget for you, otherwise you must do it with + * SetWidgetGeometry. + * + */ +WIDGET_API void XPPlaceWidgetWithin( + XPWidgetID inSubWidget, + XPWidgetID inContainer); + +/* + * XPCountChildWidgets + * + * This routine returns the number of widgets another widget contains. + * + */ +WIDGET_API int XPCountChildWidgets( + XPWidgetID inWidget); + +/* + * XPGetNthChildWidget + * + * This routine returns the widget ID of a child widget by index. Indexes are + * 0 based, from 0 to one minus the number of widgets in the parent, + * inclusive. If the index is invalid, 0 is returned. + * + */ +WIDGET_API XPWidgetID XPGetNthChildWidget( + XPWidgetID inWidget, + int inIndex); + +/* + * XPGetParentWidget + * + * Returns the parent of a widget, or 0 if the widget has no parent. Root + * widgets never have parents and therefore always return 0. + * + */ +WIDGET_API XPWidgetID XPGetParentWidget( + XPWidgetID inWidget); + +/* + * XPShowWidget + * + * This routine makes a widget visible if it is not already. Note that if a + * widget is not in a rooted widget hierarchy or one of its parents is not + * visible, it will still not be visible to the user. + * + */ +WIDGET_API void XPShowWidget( + XPWidgetID inWidget); + +/* + * XPHideWidget + * + * Makes a widget invisible. See XPShowWidget for considerations of when a + * widget might not be visible despite its own visibility state. + * + */ +WIDGET_API void XPHideWidget( + XPWidgetID inWidget); + +/* + * XPIsWidgetVisible + * + * This returns 1 if a widget is visible, 0 if it is not. Note that this + * routine takes into consideration whether a parent is invisible. Use this + * routine to tell if the user can see the widget. + * + */ +WIDGET_API int XPIsWidgetVisible( + XPWidgetID inWidget); + +/* + * XPFindRootWidget + * + * Returns the Widget ID of the root widget that contains the passed in widget + * or NULL if the passed in widget is not in a rooted hierarchy. + * + */ +WIDGET_API XPWidgetID XPFindRootWidget( + XPWidgetID inWidget); + +/* + * XPBringRootWidgetToFront + * + * This routine makes the specified widget be in the front most widget + * hierarchy. If this widget is a root widget, its widget hierarchy comes to + * front, otherwise the widget's root is brought to the front. If this widget + * is not in an active widget hiearchy (e.g. there is no root widget at the + * top of the tree), this routine does nothing. + * + */ +WIDGET_API void XPBringRootWidgetToFront( + XPWidgetID inWidget); + +/* + * XPIsWidgetInFront + * + * This routine returns true if this widget's hierarchy is the front most + * hierarchy. It returns false if the widget's hierarchy is not in front, or + * if the widget is not in a rooted hierarchy. + * + */ +WIDGET_API int XPIsWidgetInFront( + XPWidgetID inWidget); + +/* + * XPGetWidgetGeometry + * + * This routine returns the bounding box of a widget in global coordinates. + * Pass NULL for any parameter you are not interested in. + * + */ +WIDGET_API void XPGetWidgetGeometry( + XPWidgetID inWidget, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/* + * XPSetWidgetGeometry + * + * This function changes the bounding box of a widget. + * + */ +WIDGET_API void XPSetWidgetGeometry( + XPWidgetID inWidget, + int inLeft, + int inTop, + int inRight, + int inBottom); + +/* + * XPGetWidgetForLocation + * + * Given a widget and a location, this routine returns the widget ID of the + * child of that widget that owns that location. If inRecursive is true then + * this will return a child of a child of a widget as it tries to find the + * deepest widget at that location. If inVisibleOnly is true, then only + * visible widgets are considered, otherwise all widgets are considered. The + * widget ID passed for inContainer will be returned if the location is in + * that widget but not in a child widget. 0 is returned if the location is not + * in the container. + * + * NOTE: if a widget's geometry extends outside its parents geometry, it will + * not be returned by this call for mouse locations outside the parent + * geometry. The parent geometry limits the child's eligibility for mouse + * location. + * + */ +WIDGET_API XPWidgetID XPGetWidgetForLocation( + XPWidgetID inContainer, + int inXOffset, + int inYOffset, + int inRecursive, + int inVisibleOnly); + +/* + * XPGetWidgetExposedGeometry + * + * This routine returns the bounds of the area of a widget that is completely + * within its parent widgets. Since a widget's bounding box can be outside its + * parent, part of its area will not be elligible for mouse clicks and should + * not draw. Use XPGetWidgetGeometry to find out what area defines your + * widget's shape, but use this routine to find out what area to actually draw + * into. Note that the widget library does not use OpenGL clipping to keep + * frame rates up, although you could use it internally. + * + */ +WIDGET_API void XPGetWidgetExposedGeometry( + XPWidgetID inWidgetID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/*************************************************************************** + * ACCESSING WIDGET DATA + ***************************************************************************/ + +/* + * XPSetWidgetDescriptor + * + * Every widget has a descriptor, which is a text string. What the text string + * is used for varies from widget to widget; for example, a push button's text + * is its descriptor, a caption shows its descriptor, and a text field's + * descriptor is the text being edited. In other words, the usage for the text + * varies from widget to widget, but this API provides a universal and + * convenient way to get at it. While not all UI widgets need their + * descriptor, many do. + * + */ +WIDGET_API void XPSetWidgetDescriptor( + XPWidgetID inWidget, + const char * inDescriptor); + +/* + * XPGetWidgetDescriptor + * + * This routine returns the widget's descriptor. Pass in the length of the + * buffer you are going to receive the descriptor in. The descriptor will be + * null terminated for you. This routine returns the length of the actual + * descriptor; if you pass NULL for outDescriptor, you can get the + * descriptor's length without getting its text. If the length of the + * descriptor exceeds your buffer length, the buffer will not be null + * terminated (this routine has 'strncpy' semantics). + * + */ +WIDGET_API int XPGetWidgetDescriptor( + XPWidgetID inWidget, + char * outDescriptor, + int inMaxDescLength); + +/* + * XPGetWidgetUnderlyingWindow + * + * Returns the window (from the XPLMDisplay API) that backs your widget + * window. If you have opted in to modern windows, via a call to + * XPLMEnableFeature("XPLM_USE_NATIVE_WIDGET_WINDOWS", 1), you can use the + * returned window ID for display APIs like XPLMSetWindowPositioningMode(), + * allowing you to pop the widget window out into a real OS window, or move it + * into VR. + * + */ +WIDGET_API XPLMWindowID XPGetWidgetUnderlyingWindow( + XPWidgetID inWidget); + +/* + * XPSetWidgetProperty + * + * This function sets a widget's property. Properties are arbitrary values + * associated by a widget by ID. + * + */ +WIDGET_API void XPSetWidgetProperty( + XPWidgetID inWidget, + XPWidgetPropertyID inProperty, + intptr_t inValue); + +/* + * XPGetWidgetProperty + * + * This routine returns the value of a widget's property, or 0 if the property + * is not defined. If you need to know whether the property is defined, pass a + * pointer to an int for inExists; the existence of that property will be + * returned in the int. Pass NULL for inExists if you do not need this + * information. + * + */ +WIDGET_API intptr_t XPGetWidgetProperty( + XPWidgetID inWidget, + XPWidgetPropertyID inProperty, + int * inExists); /* Can be NULL */ + +/*************************************************************************** + * KEYBOARD MANAGEMENT + ***************************************************************************/ + +/* + * XPSetKeyboardFocus + * + * Controls which widget will receive keystrokes. Pass the widget ID of the + * widget to get the keys. Note that if the widget does not care about + * keystrokes, they will go to the parent widget, and if no widget cares about + * them, they go to X-Plane. + * + * If you set the keyboard focus to widget ID 0, X-Plane gets keyboard focus. + * + * This routine returns the widget ID that ended up with keyboard focus, or 0 + * for X-Plane. + * + * Keyboard focus is not changed if the new widget will not accept it. For + * setting to X-Plane, keyboard focus is always accepted. + * + */ +WIDGET_API XPWidgetID XPSetKeyboardFocus( + XPWidgetID inWidget); + +/* + * XPLoseKeyboardFocus + * + * This causes the specified widget to lose focus; focus is passed to its + * parent, or the next parent that will accept it. This routine does nothing + * if this widget does not have focus. + * + */ +WIDGET_API void XPLoseKeyboardFocus( + XPWidgetID inWidget); + +/* + * XPGetWidgetWithFocus + * + * This routine returns the widget that has keyboard focus, or 0 if X-Plane + * has keyboard focus or some other plugin window that does not have widgets + * has focus. + * + */ +WIDGET_API XPWidgetID XPGetWidgetWithFocus(void); + +/*************************************************************************** + * CREATING CUSTOM WIDGETS + ***************************************************************************/ + +/* + * XPAddWidgetCallback + * + * This function adds a new widget callback to a widget. This widget callback + * supercedes any existing ones and will receive messages first; if it does + * not handle messages they will go on to be handled by pre-existing widgets. + * + * The widget function will remain on the widget for the life of the widget. + * The creation message will be sent to the new callback immediately with the + * widget ID, and the destruction message will be sent before the other widget + * function receives a destruction message. + * + * This provides a way to 'subclass' an existing widget. By providing a second + * hook that only handles certain widget messages, you can customize or extend + * widget behavior. + * + */ +WIDGET_API void XPAddWidgetCallback( + XPWidgetID inWidget, + XPWidgetFunc_t inNewCallback); + +/* + * XPGetWidgetClassFunc + * + * Given a widget class, this function returns the callbacks that power that + * widget class. + * + */ +WIDGET_API XPWidgetFunc_t XPGetWidgetClassFunc( + XPWidgetClass inWidgetClass); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp new file mode 100644 index 0000000..5fe6218 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp @@ -0,0 +1,56 @@ +#include "XPCBroadcaster.h" +#include "XPCListener.h" + +XPCBroadcaster::XPCBroadcaster() : + mIterator(NULL) +{ +} + +XPCBroadcaster::~XPCBroadcaster() +{ + ListenerVector::iterator iter; + mIterator = &iter; + for (iter = mListeners.begin(); iter != mListeners.end(); ++iter) + { + (*iter)->BroadcasterRemoved(this); + } +} + +void XPCBroadcaster::AddListener( + XPCListener * inListener) +{ + mListeners.push_back(inListener); + inListener->BroadcasterAdded(this); +} + +void XPCBroadcaster::RemoveListener( + XPCListener * inListener) +{ + ListenerVector::iterator iter = std::find + (mListeners.begin(), mListeners.end(), inListener); + if (iter == mListeners.end()) + return; + + if (mIterator != NULL) + { + if (*mIterator >= iter) + (*mIterator)--; + } + + mListeners.erase(iter); + inListener->BroadcasterRemoved(this); +} + +void XPCBroadcaster::BroadcastMessage( + int inMessage, + void * inParam) +{ + ListenerVector::iterator iter; + mIterator = &iter; + for (iter = mListeners.begin(); iter != mListeners.end(); ++iter) + { + (*iter)->ListenToMessage(inMessage, inParam); + } + mIterator = NULL; +} + diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCBroadcaster.h b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCBroadcaster.h new file mode 100644 index 0000000..8f34a05 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCBroadcaster.h @@ -0,0 +1,38 @@ +#ifndef _XPCBroadcaster_h_ +#define _XPCBroadcaster_h_ + +#include +#include + +class XPCListener; + +class XPCBroadcaster { +public: + + XPCBroadcaster(); + virtual ~XPCBroadcaster(); + + void AddListener( + XPCListener * inListener); + void RemoveListener( + XPCListener * inListener); + +protected: + + void BroadcastMessage( + int inMessage, + void * inParam=0); + +private: + + typedef std::vector ListenerVector; + + ListenerVector mListeners; + + // Reentrancy support + + ListenerVector::iterator * mIterator; + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCDisplay.cpp b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCDisplay.cpp new file mode 100644 index 0000000..fc996ca --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCDisplay.cpp @@ -0,0 +1,104 @@ +#include "XPCDisplay.h" + +XPCKeySniffer::XPCKeySniffer(int inBeforeWindows) : mBeforeWindows(inBeforeWindows) +{ + XPLMRegisterKeySniffer(KeySnifferCB, mBeforeWindows, reinterpret_cast(this)); +} + +XPCKeySniffer::~XPCKeySniffer() +{ + XPLMUnregisterKeySniffer(KeySnifferCB, mBeforeWindows, reinterpret_cast(this)); +} + + +int XPCKeySniffer::KeySnifferCB( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefCon) +{ + XPCKeySniffer * me = reinterpret_cast(inRefCon); + return me->HandleKeyStroke(inCharKey, inFlags, inVirtualKey); +} + +XPCWindow::XPCWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible) +{ + mWindow = XPLMCreateWindow(inLeft, inTop, inRight, inBottom, inIsVisible, + DrawCB, HandleKeyCB, MouseClickCB, + reinterpret_cast(this)); +} + +XPCWindow::~XPCWindow() +{ + XPLMDestroyWindow(mWindow); +} + +void XPCWindow::GetWindowGeometry( + int * outLeft, + int * outTop, + int * outRight, + int * outBottom) +{ + XPLMGetWindowGeometry(mWindow, outLeft, outTop, outRight, outBottom); +} + +void XPCWindow::SetWindowGeometry( + int inLeft, + int inTop, + int inRight, + int inBottom) +{ + XPLMSetWindowGeometry(mWindow, inLeft, inTop, inRight, inBottom); +} + +int XPCWindow::GetWindowIsVisible(void) +{ + return XPLMGetWindowIsVisible(mWindow); +} + +void XPCWindow::SetWindowIsVisible( + int inIsVisible) +{ + XPLMSetWindowIsVisible(mWindow, inIsVisible); +} + +void XPCWindow::TakeKeyboardFocus(void) +{ + XPLMTakeKeyboardFocus(mWindow); +} + +void XPCWindow::BringWindowToFront(void) +{ + XPLMBringWindowToFront(mWindow); +} + +int XPCWindow::IsWindowInFront(void) +{ + return XPLMIsWindowInFront(mWindow); +} + +void XPCWindow::DrawCB(XPLMWindowID inWindowID, void * inRefcon) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + me->DoDraw(); +} + +void XPCWindow::HandleKeyCB(XPLMWindowID inWindowID, char inKey, XPLMKeyFlags inFlags, char inVirtualKey, void * inRefcon, int losingFocus) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + if (losingFocus) + me->LoseFocus(); + else + me->HandleKey(inKey, inFlags, inVirtualKey); +} + +int XPCWindow::MouseClickCB(XPLMWindowID inWindowID, int x, int y, XPLMMouseStatus inMouse, void * inRefcon) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + return me->HandleClick(x, y, inMouse); +} diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCDisplay.h b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCDisplay.h new file mode 100644 index 0000000..2465928 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCDisplay.h @@ -0,0 +1,73 @@ +#ifndef _XPCDisplay_h_ +#define _XPCDisplay_h_ + +#include "XPLMDisplay.h" + +class XPCKeySniffer { +public: + + XPCKeySniffer(int inBeforeWindows); + virtual ~XPCKeySniffer(); + + virtual int HandleKeyStroke( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey)=0; + +private: + + int mBeforeWindows; + + static int KeySnifferCB( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefCon); +}; + + + +class XPCWindow { +public: + + XPCWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible); + virtual ~XPCWindow(); + + virtual void DoDraw(void)=0; + virtual void HandleKey(char inKey, XPLMKeyFlags inFlags, char inVirtualKey)=0; + virtual void LoseFocus(void)=0; + virtual int HandleClick(int x, int y, XPLMMouseStatus inMouse)=0; + + void GetWindowGeometry( + int * outLeft, + int * outTop, + int * outRight, + int * outBottom); + void SetWindowGeometry( + int inLeft, + int inTop, + int inRight, + int inBottom); + int GetWindowIsVisible(void); + void SetWindowIsVisible( + int inIsVisible); + void TakeKeyboardFocus(void); + void BringWindowToFront(void); + int IsWindowInFront(void); + +private: + + XPLMWindowID mWindow; + + static void DrawCB(XPLMWindowID inWindowID, void * inRefcon); + static void HandleKeyCB(XPLMWindowID inWindowID, char inKey, XPLMKeyFlags inFlags, char inVirtualKey, void * inRefcon, int losingFocus); + static int MouseClickCB(XPLMWindowID inWindowID, int x, int y, XPLMMouseStatus inMouse, void * inRefcon); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCListener.cpp b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCListener.cpp new file mode 100644 index 0000000..b4c77aa --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCListener.cpp @@ -0,0 +1,27 @@ +#include "XPCListener.h" +#include "XPCBroadcaster.h" + +XPCListener::XPCListener() +{ +} + +XPCListener::~XPCListener() +{ + while (!mBroadcasters.empty()) + mBroadcasters.front()->RemoveListener(this); +} + +void XPCListener::BroadcasterAdded( + XPCBroadcaster * inBroadcaster) +{ + mBroadcasters.push_back(inBroadcaster); +} + +void XPCListener::BroadcasterRemoved( + XPCBroadcaster * inBroadcaster) +{ + BroadcastVector::iterator iter = std::find(mBroadcasters.begin(), + mBroadcasters.end(), inBroadcaster); + if (iter != mBroadcasters.end()) + mBroadcasters.erase(iter); +} diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCListener.h b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCListener.h new file mode 100644 index 0000000..dbdd2a0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCListener.h @@ -0,0 +1,36 @@ +#ifndef _XPCListener_h_ +#define _XPCListener_h_ + +#include +#include + +class XPCBroadcaster; + + +class XPCListener { +public: + + XPCListener(); + virtual ~XPCListener(); + + virtual void ListenToMessage( + int inMessage, + void * inParam)=0; + +private: + + typedef std::vector BroadcastVector; + + BroadcastVector mBroadcasters; + + friend class XPCBroadcaster; + + void BroadcasterAdded( + XPCBroadcaster * inBroadcaster); + + void BroadcasterRemoved( + XPCBroadcaster * inBroadcaster); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCProcessing.cpp b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCProcessing.cpp new file mode 100644 index 0000000..352c05f --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCProcessing.cpp @@ -0,0 +1,52 @@ +#include "XPCProcessing.h" +#include "XPLMUtilities.h" + +XPCProcess::XPCProcess() : + mInCallback(false), + mCallbackTime(0) +{ + XPLMRegisterFlightLoopCallback(FlightLoopCB, 0, reinterpret_cast(this)); +} + +XPCProcess::~XPCProcess() +{ + XPLMUnregisterFlightLoopCallback(FlightLoopCB, reinterpret_cast(this)); +} + +void XPCProcess::StartProcessTime(float inSeconds) +{ + mCallbackTime = inSeconds; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + +void XPCProcess::StartProcessCycles(int inCycles) +{ + mCallbackTime = -inCycles; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + +void XPCProcess::StopProcess(void) +{ + mCallbackTime = 0; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + + +float XPCProcess::FlightLoopCB( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon) +{ + XPCProcess * me = reinterpret_cast(inRefcon); + me->mInCallback = true; + me->DoProcessing(inElapsedSinceLastCall, inElapsedTimeSinceLastFlightLoop, inCounter); + me->mInCallback = false; + return me->mCallbackTime; +} \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCProcessing.h b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCProcessing.h new file mode 100644 index 0000000..cd735e5 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCProcessing.h @@ -0,0 +1,37 @@ +#ifndef _XPCProcessing_h_ +#define _XPCProcessing_h_ + +#include "XPLMProcessing.h" + +class XPCProcess { +public: + + XPCProcess(); + virtual ~XPCProcess(); + + void StartProcessTime(float inSeconds); + void StartProcessCycles(int inCycles); + void StopProcess(void); + + virtual void DoProcessing( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter)=0; + +private: + + static float FlightLoopCB( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon); + + bool mInCallback; + float mCallbackTime; + + XPCProcess(const XPCProcess&); + XPCProcess& operator=(const XPCProcess&); + +}; + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidget.cpp b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidget.cpp new file mode 100644 index 0000000..8ef8aa3 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidget.cpp @@ -0,0 +1,123 @@ +#include "XPCWidget.h" + +XPCWidget::XPCWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + bool inVisible, + const char * inDescriptor, + bool inIsRoot, + XPWidgetID inParent, + XPWidgetClass inClass) : + mWidget(NULL), + mOwnsChildren(false), + mOwnsWidget(true) +{ + mWidget = XPCreateWidget( + inLeft, inTop, inRight, inBottom, + inVisible ? 1 : 0, + inDescriptor, + inIsRoot ? 1 : 0, + inIsRoot ? NULL : inParent, + inClass); + + XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); + XPAddWidgetCallback(mWidget, WidgetCallback); +} + +XPCWidget::XPCWidget( + XPWidgetID inWidget, + bool inOwnsWidget) : + mWidget(inWidget), + mOwnsChildren(false), + mOwnsWidget(inOwnsWidget) +{ + XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); + XPAddWidgetCallback(mWidget, WidgetCallback); +} + +XPCWidget::~XPCWidget() +{ + if (mOwnsWidget) + XPDestroyWidget(mWidget, mOwnsChildren ? 1 : 0); +} + +void XPCWidget::SetOwnsWidget( + bool inOwnsWidget) +{ + mOwnsWidget = inOwnsWidget; +} + +void XPCWidget::SetOwnsChildren( + bool inOwnsChildren) +{ + mOwnsChildren = inOwnsChildren; +} + +XPCWidget::operator XPWidgetID () const +{ + return mWidget; +} + +XPWidgetID XPCWidget::Get(void) const +{ + return mWidget; +} + +void XPCWidget::AddAttachment( + XPCWidgetAttachment * inAttachment, + bool inOwnsAttachment, + bool inPrefilter) +{ + if (inPrefilter) + { + mAttachments.insert(mAttachments.begin(), AttachmentInfo(inAttachment, inOwnsAttachment)); + } else { + mAttachments.push_back(AttachmentInfo(inAttachment, inOwnsAttachment)); + } +} + +void XPCWidget::RemoveAttachment( + XPCWidgetAttachment * inAttachment) +{ + for (AttachmentVector::iterator iter = mAttachments.begin(); + iter != mAttachments.end(); ++iter) + { + if (iter->first == inAttachment) + { + mAttachments.erase(iter); + return; + } + } +} + +int XPCWidget::HandleWidgetMessage( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + return 0; +} + +int XPCWidget::WidgetCallback( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + XPCWidget * me = reinterpret_cast(XPGetWidgetProperty(inWidget, xpProperty_Object, NULL)); + if (me == NULL) + return 0; + + for (AttachmentVector::iterator iter = me->mAttachments.begin(); iter != + me->mAttachments.end(); ++iter) + { + int result = iter->first->HandleWidgetMessage(me, inMessage, inWidget, inParam1, inParam2); + if (result != 0) + return result; + } + + return me->HandleWidgetMessage(inMessage, inWidget, inParam1, inParam2); +} diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidget.h b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidget.h new file mode 100644 index 0000000..788b56a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidget.h @@ -0,0 +1,84 @@ +#ifndef _XPCWidget_h_ +#define _XPCWidget_h_ + +#include +#include +#include "XPWidgets.h" + +class XPCWidget; + +class XPCWidgetAttachment { +public: + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2)=0; + +}; + +class XPCWidget { +public: + + XPCWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + bool inVisible, + const char * inDescriptor, + bool inIsRoot, + XPWidgetID inParent, + XPWidgetClass inClass); + XPCWidget( + XPWidgetID inWidget, + bool inOwnsWidget); + virtual ~XPCWidget(); + + void SetOwnsWidget( + bool inOwnsWidget); + void SetOwnsChildren( + bool inOwnsChildren); + + operator XPWidgetID () const; + + XPWidgetID Get(void) const; + + void AddAttachment( + XPCWidgetAttachment * inAttachment, + bool inOwnsAttachment, + bool inPrefilter); + void RemoveAttachment( + XPCWidgetAttachment * inAttachment); + + virtual int HandleWidgetMessage( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + static int WidgetCallback( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + + typedef std::pair AttachmentInfo; + typedef std::vector AttachmentVector; + + AttachmentVector mAttachments; + XPWidgetID mWidget; + bool mOwnsChildren; + bool mOwnsWidget; + + XPCWidget(); + XPCWidget(const XPCWidget&); + XPCWidget& operator=(const XPCWidget&); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp new file mode 100644 index 0000000..d87f105 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp @@ -0,0 +1,267 @@ +#include "XPCWidgetAttachments.h" +#include "XPStandardWidgets.h" +#include "XPWidgetUtils.h" + +static void XPCGetOrderedSubWidgets( + XPWidgetID inWidget, + std::vector& outChildren); + +XPCKeyFilterAttachment::XPCKeyFilterAttachment( + const char * inValidKeys, + const char * outValidKeys) : + mInput(inValidKeys), + mOutput(outValidKeys) +{ +} + +XPCKeyFilterAttachment::~XPCKeyFilterAttachment() +{ +} + +int XPCKeyFilterAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if (inMessage == xpMsg_KeyPress) + { + char& theKey = KEY_CHAR(inParam1); + std::string::size_type pos = mInput.find(theKey); + if (pos == std::string::npos) + return 1; // Not found; eat the key! + else { + theKey = mOutput[pos]; + return 0; + } // Let it live. + } + return 0; +} + + +XPCKeyMessageAttachment::XPCKeyMessageAttachment( + char inKey, + int inMessage, + void * inParam, + bool inConsume, + bool inVkey, + XPCListener * inListener) : + mKey(inKey), mMsg(inMessage), mParam(inParam), mConsume(inConsume), + mVkey(inVkey) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCKeyMessageAttachment::~XPCKeyMessageAttachment() +{ +} + +int XPCKeyMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if (inMessage == xpMsg_KeyPress) + { + char theKey = mVkey ? KEY_VKEY(inParam1) : KEY_CHAR(inParam1); + if (theKey != mKey) + return 0; + if (!(KEY_FLAGS(inParam1) & xplm_DownFlag)) + return 0; + + BroadcastMessage(mMsg, mParam); + return mConsume ? 1 : 0; + } + return 0; +} + +XPCPushButtonMessageAttachment::XPCPushButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCPushButtonMessageAttachment::~XPCPushButtonMessageAttachment() +{ +} + +int XPCPushButtonMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_PushButtonPressed) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + if ((inMessage == xpMsg_ButtonStateChanged) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + return 0; +} + +XPCSliderMessageAttachment::XPCSliderMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCSliderMessageAttachment::~XPCSliderMessageAttachment() +{ +} + +int XPCSliderMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_ScrollBarSliderPositionChanged) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + return 0; +} + + +XPCCloseButtonMessageAttachment::XPCCloseButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCCloseButtonMessageAttachment::~XPCCloseButtonMessageAttachment() +{ +} + +int XPCCloseButtonMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMessage_CloseButtonPushed) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + return 0; +} + +XPCTabGroupAttachment::XPCTabGroupAttachment() +{ +} + +XPCTabGroupAttachment::~XPCTabGroupAttachment() +{ +} + +int XPCTabGroupAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_KeyPress) && (KEY_CHAR(inParam1) == XPLM_KEY_TAB) && + ((KEY_FLAGS(inParam1) & xplm_UpFlag) == 0)) + { + bool backwards = (KEY_FLAGS(inParam1) & xplm_ShiftFlag) != 0; + std::vector widgets; + XPCGetOrderedSubWidgets(inWidget, widgets); + int n, index = 0; + XPWidgetID focusWidget = XPGetWidgetWithFocus(); + std::vector::iterator iter = std::find(widgets.begin(), widgets.end(), focusWidget); + if (iter != widgets.end()) + { + index = std::distance(widgets.begin(), iter); + if (backwards) + index--; + else + index++; + if (index < 0) + index = widgets.size() - 1; + if (index >= widgets.size()) + index = 0; + } + + if (backwards) + { + for (n = index; n >= 0; --n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + for (n = widgets.size() - 1; n > index; --n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + } else { + for (n = index; n < widgets.size(); ++n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + for (n = 0; n < index; ++n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + } + } + return 0; +} + + + +static void XPCGetOrderedSubWidgets( + XPWidgetID inWidget, + std::vector& outChildren) +{ + outChildren.clear(); + int count = XPCountChildWidgets(inWidget); + for (int n = 0; n < count; ++n) + { + XPWidgetID child = XPGetNthChildWidget(inWidget, n); + outChildren.push_back(child); + std::vector grandChildren; + XPCGetOrderedSubWidgets(child, grandChildren); + + outChildren.insert(outChildren.end(), grandChildren.begin(), grandChildren.end()); + } +} diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h new file mode 100644 index 0000000..91fb587 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h @@ -0,0 +1,146 @@ +#ifndef _XPCWidgetAttachments_h_ +#define _XPCWidgetAttachments_h_ + +#include + +#include "XPCWidget.h" +#include "XPCBroadcaster.h" + +class XPCKeyFilterAttachment : public XPCWidgetAttachment { +public: + + XPCKeyFilterAttachment( + const char * inValidKeys, + const char * outValidKeys); + virtual ~XPCKeyFilterAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + std::string mInput; + std::string mOutput; + +}; + + +class XPCKeyMessageAttachment : public XPCWidgetAttachment, public XPCBroadcaster { +public: + + XPCKeyMessageAttachment( + char inKey, + int inMessage, + void * inParam, + bool inConsume, + bool inVkey, + XPCListener * inListener); + virtual ~XPCKeyMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + char mKey; + bool mVkey; + int mMsg; + void * mParam; + bool mConsume; + +}; + +class XPCPushButtonMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCPushButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCPushButtonMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + +class XPCSliderMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCSliderMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCSliderMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + + +class XPCCloseButtonMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCCloseButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCCloseButtonMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + +class XPCTabGroupAttachment : public XPCWidgetAttachment { +public: + + XPCTabGroupAttachment(); + virtual ~XPCTabGroupAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMCamera.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMCamera.h new file mode 100644 index 0000000..db930ef --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMCamera.h @@ -0,0 +1,167 @@ +#ifndef _XPLMCamera_h_ +#define _XPLMCamera_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMCamera + ***************************************************************************/ +/* + * The XPLMCamera APIs allow plug-ins to control the camera angle in X-Plane. + * This has a number of applications, including but not limited to: + * + * - Creating new views (including dynamic/user-controllable views) for the + * user. + * - Creating applications that use X-Plane as a renderer of scenery, + * aircrafts, or both. + * + * The camera is controlled via six parameters: a location in OpenGL + * coordinates and pitch, roll and yaw, similar to an airplane's position. + * OpenGL coordinate info is described in detail in the XPLMGraphics + * documentation; generally you should use the XPLMGraphics routines to + * convert from world to local coordinates. The camera's orientation starts + * facing level with the ground directly up the negative-Z axis (approximately + * north) with the horizon horizontal. It is then rotated clockwise for yaw, + * pitched up for positive pitch, and rolled clockwise around the vector it is + * looking along for roll. + * + * You control the camera either either until the user selects a new view or + * permanently (the later being similar to how UDP camera control works). You + * control the camera by registering a callback per frame from which you + * calculate the new camera positions. This guarantees smooth camera motion. + * + * Use the XPLMDataAccess APIs to get information like the position of the + * aircraft, etc. for complex camera positioning. + * + * Note: if your goal is to move the virtual pilot in the cockpit, this API is + * not needed; simply update the datarefs for the pilot's head position. + * + * For custom exterior cameras, set the camera's mode to an external view + * first to get correct sound and 2-d panel behavior. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * CAMERA CONTROL + ***************************************************************************/ + +/* + * XPLMCameraControlDuration + * + * This enumeration states how long you want to retain control of the camera. + * You can retain it indefinitely or until the user selects a new view. + * + */ +enum { + /* Control the camera until the user picks a new view. */ + xplm_ControlCameraUntilViewChanges = 1, + + /* Control the camera until your plugin is disabled or another plugin forcably* + * takes control. */ + xplm_ControlCameraForever = 2, + + +}; +typedef int XPLMCameraControlDuration; + +/* + * XPLMCameraPosition_t + * + * This structure contains a full specification of the camera. X, Y, and Z are + * the camera's position in OpenGL coordiantes; pitch, roll, and yaw are + * rotations from a camera facing flat north in degrees. Positive pitch means + * nose up, positive roll means roll right, and positive yaw means yaw right, + * all in degrees. Zoom is a zoom factor, with 1.0 meaning normal zoom and 2.0 + * magnifying by 2x (objects appear larger). + * + */ +typedef struct { + float x; + float y; + float z; + float pitch; + float heading; + float roll; + float zoom; +} XPLMCameraPosition_t; + +/* + * XPLMCameraControl_f + * + * You use an XPLMCameraControl function to provide continuous control over + * the camera. You are passed in a structure in which to put the new camera + * position; modify it and return 1 to reposition the camera. Return 0 to + * surrender control of the camera; camera control will be handled by X-Plane + * on this draw loop. The contents of the structure as you are called are + * undefined. + * + * If X-Plane is taking camera control away from you, this function will be + * called with inIsLosingControl set to 1 and ioCameraPosition NULL. + * + */ +typedef int (* XPLMCameraControl_f)( + XPLMCameraPosition_t * outCameraPosition, /* Can be NULL */ + int inIsLosingControl, + void * inRefcon); + +/* + * XPLMControlCamera + * + * This function repositions the camera on the next drawing cycle. You must + * pass a non-null control function. Specify in inHowLong how long you'd like + * control (indefinitely or until a new view mode is set by the user). + * + */ +XPLM_API void XPLMControlCamera( + XPLMCameraControlDuration inHowLong, + XPLMCameraControl_f inControlFunc, + void * inRefcon); + +/* + * XPLMDontControlCamera + * + * This function stops you from controlling the camera. If you have a camera + * control function, it will not be called with an inIsLosingControl flag. + * X-Plane will control the camera on the next cycle. + * + * For maximum compatibility you should not use this routine unless you are in + * posession of the camera. + * + */ +XPLM_API void XPLMDontControlCamera(void); + +/* + * XPLMIsCameraBeingControlled + * + * This routine returns 1 if the camera is being controlled, zero if it is + * not. If it is and you pass in a pointer to a camera control duration, the + * current control duration will be returned. + * + */ +XPLM_API int XPLMIsCameraBeingControlled( + XPLMCameraControlDuration * outCameraControlDuration); /* Can be NULL */ + +/* + * XPLMReadCameraPosition + * + * This function reads the current camera position. + * + */ +XPLM_API void XPLMReadCameraPosition( + XPLMCameraPosition_t * outCameraPosition); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDataAccess.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDataAccess.h new file mode 100644 index 0000000..d8d1418 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDataAccess.h @@ -0,0 +1,716 @@ +#ifndef _XPLMDataAccess_h_ +#define _XPLMDataAccess_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDataAccess + ***************************************************************************/ +/* + * The data access API gives you a generic, flexible, high performance way to + * read and write data to and from X-Plane and other plug-ins. For example, + * this API allows you to read and set the nav radios, get the plane location, + * determine the current effective graphics frame rate, etc. + * + * The data access APIs are the way that you read and write data from the sim + * as well as other plugins. + * + * The API works using opaque data references. A data reference is a source of + * data; you do not know where it comes from, but once you have it you can + * read the data quickly and possibly write it. + * + * Dataref Lookup + * -------------- + * + * Data references are identified by verbose, permanent string names; by + * convention these names use path separates to form a hierarchy of datarefs, + * e.g. (sim/cockpit/radios/nav1_freq_hz). The actual opaque numeric value of + * the data reference, as returned by the XPLM API, is implementation defined + * and changes each time X-Plane is launched; therefore you need to look up + * the dataref by path every time your plugin runs. + * + * The task of looking up a data reference is relatively expensive; look up + * your data references once based on the verbose path strings, and save the + * opaque data reference value for the duration of your plugin's operation. + * Reading and writing data references is relatively fast (the cost is + * equivalent to two function calls through function pointers). + * + * X-Plane publishes over 4000 datarefs; a complete list may be found in the + * reference section of the SDK online documentation (from the SDK home page, + * choose Documentation). + * + * Dataref Types + * ------------- + * + * A note on typing: you must know the correct data type to read and write. + * APIs are provided for reading and writing data in a number of ways. You can + * also double check the data type for a data ref. Automatic type conversion + * is not done for you. + * + * Dataref types are a set, e.g. a dataref can be more than one type. When + * this happens, you can choose which API you want to use to read. For + * example, it is not uncommon for a dataref to be of type float and double. + * This means you can use either XPLMGetDatad or XPLMGetDataf to read it. + * + * Creating New Datarefs + * --------------------- + * + * X-Plane provides datarefs that come with the sim, but plugins can also + * create their own datarefs. A plugin creates a dataref by registering + * function callbacks to read and write the dataref. The XPLM will call your + * plugin each time some other plugin (or X-Plane) tries to read or write the + * dataref. You must provide a read (and optional write) callback for each + * data type you support. + * + * A note for plugins sharing data with other plugins: the load order of + * plugins is not guaranteed. To make sure that every plugin publishing data + * has published their data references before other plugins try to subscribe, + * publish your data references in your start routine but resolve them the + * first time your 'enable' routine is called, or the first time they are + * needed in code. + * + * When a plugin that created a dataref is unloaded, it becomes "orphaned". + * The dataref handle continues to be usable, but the dataref is not writable, + * and reading it will always return 0 (or 0 items for arrays). If the plugin + * is reloaded and re-registers the dataref, the handle becomes un-orphaned + * and works again. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * READING AND WRITING DATA + ***************************************************************************/ +/* + * These routines allow you to access data from within X-Plane and sometimes + * modify it. + * + */ + + +/* + * XPLMDataRef + * + * A data ref is an opaque handle to data provided by the simulator or another + * plugin. It uniquely identifies one variable (or array of variables) over + * the lifetime of your plugin. You never hard code these values; you always + * get them from XPLMFindDataRef. + * + */ +typedef void * XPLMDataRef; + +/* + * XPLMDataTypeID + * + * This is an enumeration that defines the type of the data behind a data + * reference. This allows you to sanity check that the data type matches what + * you expect. But for the most part, you will know the type of data you are + * expecting from the online documentation. + * + * Data types each take a bit field; it is legal to have a single dataref be + * more than one type of data. Whe this happens, you can pick any matching + * get/set API. + * + */ +enum { + /* Data of a type the current XPLM doesn't do. */ + xplmType_Unknown = 0, + + /* A single 4-byte integer, native endian. */ + xplmType_Int = 1, + + /* A single 4-byte float, native endian. */ + xplmType_Float = 2, + + /* A single 8-byte double, native endian. */ + xplmType_Double = 4, + + /* An array of 4-byte floats, native endian. */ + xplmType_FloatArray = 8, + + /* An array of 4-byte integers, native endian. */ + xplmType_IntArray = 16, + + /* A variable block of data. */ + xplmType_Data = 32, + + +}; +typedef int XPLMDataTypeID; + +/* + * XPLMFindDataRef + * + * Given a c-style string that names the data ref, this routine looks up the + * actual opaque XPLMDataRef that you use to read and write the data. The + * string names for datarefs are published on the X-Plane SDK web site. + * + * This function returns NULL if the data ref cannot be found. + * + * NOTE: this function is relatively expensive; save the XPLMDataRef this + * function returns for future use. Do not look up your data ref by string + * every time you need to read or write it. + * + */ +XPLM_API XPLMDataRef XPLMFindDataRef( + const char * inDataRefName); + +/* + * XPLMCanWriteDataRef + * + * Given a data ref, this routine returns true if you can successfully set the + * data, false otherwise. Some datarefs are read-only. + * + * NOTE: even if a dataref is marked writable, it may not act writable. This + * can happen for datarefs that X-Plane writes to on every frame of + * simulation. In some cases, the dataref is writable but you have to set a + * separate "override" dataref to 1 to stop X-Plane from writing it. + * + */ +XPLM_API int XPLMCanWriteDataRef( + XPLMDataRef inDataRef); + +/* + * XPLMIsDataRefGood + * + * This function returns true if the passed in handle is a valid dataref that + * is not orphaned. + * + * Note: there is normally no need to call this function; datarefs returned by + * XPLMFindDataRef remain valid (but possibly orphaned) unless there is a + * complete plugin reload (in which case your plugin is reloaded anyway). + * Orphaned datarefs can be safely read and return 0. Therefore you never need + * to call XPLMIsDataRefGood to 'check' the safety of a dataref. + * (XPLMIsDatarefGood performs some slow checking of the handle validity, so + * it has a perormance cost.) + * + */ +XPLM_API int XPLMIsDataRefGood( + XPLMDataRef inDataRef); + +/* + * XPLMGetDataRefTypes + * + * This routine returns the types of the data ref for accessor use. If a data + * ref is available in multiple data types, the bit-wise OR of these types + * will be returned. + * + */ +XPLM_API XPLMDataTypeID XPLMGetDataRefTypes( + XPLMDataRef inDataRef); + +/*************************************************************************** + * DATA ACCESSORS + ***************************************************************************/ +/* + * These routines read and write the data references. For each supported data + * type there is a reader and a writer. + * + * If the data ref is orphaned or the plugin that provides it is disabled or + * there is a type mismatch, the functions that read data will return 0 as a + * default value or not modify the passed in memory. The plugins that write + * data will not write under these circumstances or if the data ref is + * read-only. + * + * NOTE: to keep the overhead of reading datarefs low, these routines do not + * do full validation of a dataref; passing a junk value for a dataref can + * result in crashing the sim. The get/set APIs do check for NULL. + * + * For array-style datarefs, you specify the number of items to read/write and + * the offset into the array; the actual number of items read or written is + * returned. This may be less to prevent an array-out-of-bounds error. + * + */ + + +/* + * XPLMGetDatai + * + * Read an integer data ref and return its value. The return value is the + * dataref value or 0 if the dataref is NULL or the plugin is disabled. + * + */ +XPLM_API int XPLMGetDatai( + XPLMDataRef inDataRef); + +/* + * XPLMSetDatai + * + * Write a new value to an integer data ref. This routine is a no-op if the + * plugin publishing the dataref is disabled, the dataref is NULL, or the + * dataref is not writable. + * + */ +XPLM_API void XPLMSetDatai( + XPLMDataRef inDataRef, + int inValue); + +/* + * XPLMGetDataf + * + * Read a single precision floating point dataref and return its value. The + * return value is the dataref value or 0.0 if the dataref is NULL or the + * plugin is disabled. + * + */ +XPLM_API float XPLMGetDataf( + XPLMDataRef inDataRef); + +/* + * XPLMSetDataf + * + * Write a new value to a single precision floating point data ref. This + * routine is a no-op if the plugin publishing the dataref is disabled, the + * dataref is NULL, or the dataref is not writable. + * + */ +XPLM_API void XPLMSetDataf( + XPLMDataRef inDataRef, + float inValue); + +/* + * XPLMGetDatad + * + * Read a double precision floating point dataref and return its value. The + * return value is the dataref value or 0.0 if the dataref is NULL or the + * plugin is disabled. + * + */ +XPLM_API double XPLMGetDatad( + XPLMDataRef inDataRef); + +/* + * XPLMSetDatad + * + * Write a new value to a double precision floating point data ref. This + * routine is a no-op if the plugin publishing the dataref is disabled, the + * dataref is NULL, or the dataref is not writable. + * + */ +XPLM_API void XPLMSetDatad( + XPLMDataRef inDataRef, + double inValue); + +/* + * XPLMGetDatavi + * + * Read a part of an integer array dataref. If you pass NULL for outValues, + * the routine will return the size of the array, ignoring inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatavi( + XPLMDataRef inDataRef, + int * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavi + * + * Write part or all of an integer array dataref. The values passed by + * inValues are written into the dataref starting at inOffset. Up to inCount + * values are written; however if the values would write "off the end" of the + * dataref array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatavi( + XPLMDataRef inDataRef, + int * inValues, + int inoffset, + int inCount); + +/* + * XPLMGetDatavf + * + * Read a part of a single precision floating point array dataref. If you pass + * NULL for outVaules, the routine will return the size of the array, ignoring + * inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatavf( + XPLMDataRef inDataRef, + float * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavf + * + * Write part or all of a single precision floating point array dataref. The + * values passed by inValues are written into the dataref starting at + * inOffset. Up to inCount values are written; however if the values would + * write "off the end" of the dataref array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatavf( + XPLMDataRef inDataRef, + float * inValues, + int inoffset, + int inCount); + +/* + * XPLMGetDatab + * + * Read a part of a byte array dataref. If you pass NULL for outVaules, the + * routine will return the size of the array, ignoring inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatab( + XPLMDataRef inDataRef, + void * outValue, /* Can be NULL */ + int inOffset, + int inMaxBytes); + +/* + * XPLMSetDatab + * + * Write part or all of a byte array dataref. The values passed by inValues + * are written into the dataref starting at inOffset. Up to inCount values are + * written; however if the values would write "off the end" of the dataref + * array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatab( + XPLMDataRef inDataRef, + void * inValue, + int inOffset, + int inLength); + +/*************************************************************************** + * PUBLISHING YOUR PLUGIN'S DATA + ***************************************************************************/ +/* + * These functions allow you to create data references that other plug-ins and + * X-Plane can access via the above data access APIs. Data references + * published by other plugins operate the same as ones published by X-Plane in + * all manners except that your data reference will not be available to other + * plugins if/when your plugin is disabled. + * + * You share data by registering data provider callback functions. When a + * plug-in requests your data, these callbacks are then called. You provide + * one callback to return the value when a plugin 'reads' it and another to + * change the value when a plugin 'writes' it. + * + * Important: you must pick a prefix for your datarefs other than "sim/" - + * this prefix is reserved for X-Plane. The X-Plane SDK website contains a + * registry where authors can select a unique first word for dataref names, to + * prevent dataref collisions between plugins. + * + */ + + +/* + * XPLMGetDatai_f + * + * Data provider function pointers. + * + * These define the function pointers you provide to get or set data. Note + * that you are passed a generic pointer for each one. This is the same + * pointer you pass in your register routine; you can use it to locate plugin + * variables, etc. + * + * The semantics of your callbacks are the same as the dataref accessor above + * - basically routines like XPLMGetDatai are just pass-throughs from a caller + * to your plugin. Be particularly mindful in implementing array dataref + * read-write accessors; you are responsible for avoiding overruns, supporting + * offset read/writes, and handling a read with a NULL buffer. + * + */ +typedef int (* XPLMGetDatai_f)( + void * inRefcon); + +/* + * XPLMSetDatai_f + * + */ +typedef void (* XPLMSetDatai_f)( + void * inRefcon, + int inValue); + +/* + * XPLMGetDataf_f + * + */ +typedef float (* XPLMGetDataf_f)( + void * inRefcon); + +/* + * XPLMSetDataf_f + * + */ +typedef void (* XPLMSetDataf_f)( + void * inRefcon, + float inValue); + +/* + * XPLMGetDatad_f + * + */ +typedef double (* XPLMGetDatad_f)( + void * inRefcon); + +/* + * XPLMSetDatad_f + * + */ +typedef void (* XPLMSetDatad_f)( + void * inRefcon, + double inValue); + +/* + * XPLMGetDatavi_f + * + */ +typedef int (* XPLMGetDatavi_f)( + void * inRefcon, + int * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavi_f + * + */ +typedef void (* XPLMSetDatavi_f)( + void * inRefcon, + int * inValues, + int inOffset, + int inCount); + +/* + * XPLMGetDatavf_f + * + */ +typedef int (* XPLMGetDatavf_f)( + void * inRefcon, + float * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavf_f + * + */ +typedef void (* XPLMSetDatavf_f)( + void * inRefcon, + float * inValues, + int inOffset, + int inCount); + +/* + * XPLMGetDatab_f + * + */ +typedef int (* XPLMGetDatab_f)( + void * inRefcon, + void * outValue, /* Can be NULL */ + int inOffset, + int inMaxLength); + +/* + * XPLMSetDatab_f + * + */ +typedef void (* XPLMSetDatab_f)( + void * inRefcon, + void * inValue, + int inOffset, + int inLength); + +/* + * XPLMRegisterDataAccessor + * + * This routine creates a new item of data that can be read and written. Pass + * in the data's full name for searching, the type(s) of the data for + * accessing, and whether the data can be written to. For each data type you + * support, pass in a read accessor function and a write accessor function if + * necessary. Pass NULL for data types you do not support or write accessors + * if you are read-only. + * + * You are returned a data ref for the new item of data created. You can use + * this data ref to unregister your data later or read or write from it. + * + */ +XPLM_API XPLMDataRef XPLMRegisterDataAccessor( + const char * inDataName, + XPLMDataTypeID inDataType, + int inIsWritable, + XPLMGetDatai_f inReadInt, + XPLMSetDatai_f inWriteInt, + XPLMGetDataf_f inReadFloat, + XPLMSetDataf_f inWriteFloat, + XPLMGetDatad_f inReadDouble, + XPLMSetDatad_f inWriteDouble, + XPLMGetDatavi_f inReadIntArray, + XPLMSetDatavi_f inWriteIntArray, + XPLMGetDatavf_f inReadFloatArray, + XPLMSetDatavf_f inWriteFloatArray, + XPLMGetDatab_f inReadData, + XPLMSetDatab_f inWriteData, + void * inReadRefcon, + void * inWriteRefcon); + +/* + * XPLMUnregisterDataAccessor + * + * Use this routine to unregister any data accessors you may have registered. + * You unregister a data ref by the XPLMDataRef you get back from + * registration. Once you unregister a data ref, your function pointer will + * not be called anymore. + * + */ +XPLM_API void XPLMUnregisterDataAccessor( + XPLMDataRef inDataRef); + +/*************************************************************************** + * SHARING DATA BETWEEN MULTIPLE PLUGINS + ***************************************************************************/ +/* + * The data reference registration APIs from the previous section allow a + * plugin to publish data in a one-owner manner; the plugin that publishes the + * data reference owns the real memory that the data ref uses. This is + * satisfactory for most cases, but there are also cases where plugnis need to + * share actual data. + * + * With a shared data reference, no one plugin owns the actual memory for the + * data reference; the plugin SDK allocates that for you. When the first + * plugin asks to 'share' the data, the memory is allocated. When the data is + * changed, every plugin that is sharing the data is notified. + * + * Shared data references differ from the 'owned' data references from the + * previous section in a few ways: + * + * * With shared data references, any plugin can create the data reference; + * with owned plugins one plugin must create the data reference and others + * subscribe. (This can be a problem if you don't know which set of plugins + * will be present). + * + * * With shared data references, every plugin that is sharing the data is + * notified when the data is changed. With owned data references, only the + * one owner is notified when the data is changed. + * + * * With shared data references, you cannot access the physical memory of the + * data reference; you must use the XPLMGet... and XPLMSet... APIs. With an + * owned data reference, the one owning data reference can manipulate the + * data reference's memory in any way it sees fit. + * + * Shared data references solve two problems: if you need to have a data + * reference used by several plugins but do not know which plugins will be + * installed, or if all plugins sharing data need to be notified when that + * data is changed, use shared data references. + * + */ + + +/* + * XPLMDataChanged_f + * + * An XPLMDataChanged_f is a callback that the XPLM calls whenever any other + * plug-in modifies shared data. A refcon you provide is passed back to help + * identify which data is being changed. In response, you may want to call one + * of the XPLMGetDataxxx routines to find the new value of the data. + * + */ +typedef void (* XPLMDataChanged_f)( + void * inRefcon); + +/* + * XPLMShareData + * + * This routine connects a plug-in to shared data, creating the shared data if + * necessary. inDataName is a standard path for the data ref, and inDataType + * specifies the type. This function will create the data if it does not + * exist. If the data already exists but the type does not match, an error is + * returned, so it is important that plug-in authors collaborate to establish + * public standards for shared data. + * + * If a notificationFunc is passed in and is not NULL, that notification + * function will be called whenever the data is modified. The notification + * refcon will be passed to it. This allows your plug-in to know which shared + * data was changed if multiple shared data are handled by one callback, or if + * the plug-in does not use global variables. + * + * A one is returned for successfully creating or finding the shared data; a + * zero if the data already exists but is of the wrong type. + * + */ +XPLM_API int XPLMShareData( + const char * inDataName, + XPLMDataTypeID inDataType, + XPLMDataChanged_f inNotificationFunc, + void * inNotificationRefcon); + +/* + * XPLMUnshareData + * + * This routine removes your notification function for shared data. Call it + * when done with the data to stop receiving change notifications. Arguments + * must match XPLMShareData. The actual memory will not necessarily be freed, + * since other plug-ins could be using it. + * + */ +XPLM_API int XPLMUnshareData( + const char * inDataName, + XPLMDataTypeID inDataType, + XPLMDataChanged_f inNotificationFunc, + void * inNotificationRefcon); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDefs.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDefs.h new file mode 100644 index 0000000..bb1fe2f --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDefs.h @@ -0,0 +1,514 @@ +#ifndef _XPLMDefs_h_ +#define _XPLMDefs_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDefs + ***************************************************************************/ +/* + * This file is contains the cross-platform and basic definitions for the + * X-Plane SDK. + * + * The preprocessor macros APL and IBM must be defined to specify the + * compilation target; define APL to 1 and IBM 0 to compile on Macintosh and + * APL to 0 and IBM to 1 for Windows. You must specify these macro definitions + * before including XPLMDefs.h or any other XPLM headers. You can do this + * using the -D command line option or a preprocessor header. + * + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#if IBM +#include +#else +#include +#endif +/*************************************************************************** + * DLL Definitions + ***************************************************************************/ +/* + * These definitions control the importing and exporting of functions within + * the DLL. + * + * You can prefix your five required callbacks with the PLUGIN_API macro to + * declare them as exported C functions. The XPLM_API macro identifies + * functions that are provided to you via the plugin SDK. (Link against + * XPLM.lib to use these functions.) + * + */ + + +#ifdef __cplusplus + #if APL + #if __GNUC__ >= 4 + #define PLUGIN_API extern "C" __attribute__((visibility("default"))) + #elif __MACH__ + #define PLUGIN_API extern "C" + #else + #define PLUGIN_API extern "C" __declspec(dllexport) + #endif + #elif IBM + #define PLUGIN_API extern "C" __declspec(dllexport) + #elif LIN + #if __GNUC__ >= 4 + #define PLUGIN_API extern "C" __attribute__((visibility("default"))) + #else + #define PLUGIN_API extern "C" + #endif + #else + #error "Platform not defined!" + #endif +#else + #if APL + #if __GNUC__ >= 4 + #define PLUGIN_API __attribute__((visibility("default"))) + #elif __MACH__ + #define PLUGIN_API + #else + #define PLUGIN_API __declspec(dllexport) + #endif + #elif IBM + #define PLUGIN_API __declspec(dllexport) + #elif LIN + #if __GNUC__ >= 4 + #define PLUGIN_API __attribute__((visibility("default"))) + #else + #define PLUGIN_API + #endif + #else + #error "Platform not defined!" + #endif +#endif + +#if APL + #if XPLM + #if __GNUC__ >= 4 + #define XPLM_API __attribute__((visibility("default"))) + #elif __MACH__ + #define XPLM_API + #else + #define XPLM_API __declspec(dllexport) + #endif + #else + #define XPLM_API + #endif +#elif IBM + #if XPLM + #define XPLM_API __declspec(dllexport) + #else + #define XPLM_API __declspec(dllimport) + #endif +#elif LIN + #if XPLM + #if __GNUC__ >= 4 + #define XPLM_API __attribute__((visibility("default"))) + #else + #define XPLM_API + #endif + #else + #define XPLM_API + #endif +#else + #error "Platform not defined!" +#endif + +/*************************************************************************** + * GLOBAL DEFINITIONS + ***************************************************************************/ +/* + * These definitions are used in all parts of the SDK. + * + */ + + +/* + * XPLMPluginID + * + * Each plug-in is identified by a unique integer ID. This ID can be used to + * disable or enable a plug-in, or discover what plug-in is 'running' at the + * time. A plug-in ID is unique within the currently running instance of + * X-Plane unless plug-ins are reloaded. Plug-ins may receive a different + * unique ID each time they are loaded. This includes the unloading and + * reloading of plugins that are part of the user's aircraft. + * + * For persistent identification of plug-ins, use XPLMFindPluginBySignature in + * XPLMUtiltiies.h + * + * -1 indicates no plug-in. + * + */ +typedef int XPLMPluginID; + +/* No plugin. */ +#define XPLM_NO_PLUGIN_ID (-1) + +/* X-Plane itself */ +#define XPLM_PLUGIN_XPLANE (0) + +/* The current XPLM revision is 3.03 (303). */ +#define kXPLM_Version (303) + +/* + * XPLMKeyFlags + * + * These bitfields define modifier keys in a platform independent way. When a + * key is pressed, a series of messages are sent to your plugin. The down + * flag is set in the first of these messages, and the up flag in the last. + * While the key is held down, messages are sent with neither to indicate that + * the key is being held down as a repeated character. + * + * The control flag is mapped to the control flag on Macintosh and PC. + * Generally X-Plane uses the control key and not the command key on + * Macintosh, providing a consistent interface across platforms that does not + * necessarily match the Macintosh user interface guidelines. There is not + * yet a way for plugins to access the Macintosh control keys without using + * #ifdefed code. + * + */ +enum { + /* The shift key is down */ + xplm_ShiftFlag = 1, + + /* The option or alt key is down */ + xplm_OptionAltFlag = 2, + + /* The control key is down* */ + xplm_ControlFlag = 4, + + /* The key is being pressed down */ + xplm_DownFlag = 8, + + /* The key is being released */ + xplm_UpFlag = 16, + + +}; +typedef int XPLMKeyFlags; + +/*************************************************************************** + * ASCII CONTROL KEY CODES + ***************************************************************************/ +/* + * These definitions define how various control keys are mapped to ASCII key + * codes. Not all key presses generate an ASCII value, so plugin code should + * be prepared to see null characters come from the keyboard...this usually + * represents a key stroke that has no equivalent ASCII, like a page-down + * press. Use virtual key codes to find these key strokes. + * + * ASCII key codes take into account modifier keys; shift keys will affect + * capitals and punctuation; control key combinations may have no vaild ASCII + * and produce NULL. To detect control-key combinations, use virtual key + * codes, not ASCII keys. + * + */ + + +#define XPLM_KEY_RETURN 13 + +#define XPLM_KEY_ESCAPE 27 + +#define XPLM_KEY_TAB 9 + +#define XPLM_KEY_DELETE 8 + +#define XPLM_KEY_LEFT 28 + +#define XPLM_KEY_RIGHT 29 + +#define XPLM_KEY_UP 30 + +#define XPLM_KEY_DOWN 31 + +#define XPLM_KEY_0 48 + +#define XPLM_KEY_1 49 + +#define XPLM_KEY_2 50 + +#define XPLM_KEY_3 51 + +#define XPLM_KEY_4 52 + +#define XPLM_KEY_5 53 + +#define XPLM_KEY_6 54 + +#define XPLM_KEY_7 55 + +#define XPLM_KEY_8 56 + +#define XPLM_KEY_9 57 + +#define XPLM_KEY_DECIMAL 46 + +/*************************************************************************** + * VIRTUAL KEY CODES + ***************************************************************************/ +/* + * These are cross-platform defines for every distinct keyboard press on the + * computer. Every physical key on the keyboard has a virtual key code. So + * the "two" key on the top row of the main keyboard has a different code from + * the "two" key on the numeric key pad. But the 'w' and 'W' character are + * indistinguishable by virtual key code because they are the same physical + * key (one with and one without the shift key). + * + * Use virtual key codes to detect keystrokes that do not have ASCII + * equivalents, allow the user to map the numeric keypad separately from the + * main keyboard, and detect control key and other modifier-key combinations + * that generate ASCII control key sequences (many of which are not available + * directly via character keys in the SDK). + * + * To assign virtual key codes we started with the Microsoft set but made some + * additions and changes. A few differences: + * + * 1. Modifier keys are not available as virtual key codes. You cannot get + * distinct modifier press and release messages. Please do not try to use + * modifier keys as regular keys; doing so will almost certainly interfere + * with users' abilities to use the native X-Plane key bindings. + * 2. Some keys that do not exist on both Mac and PC keyboards are removed. + * 3. Do not assume that the values of these keystrokes are interchangeable + * with MS v-keys. + * + */ + + +#define XPLM_VK_BACK 0x08 + +#define XPLM_VK_TAB 0x09 + +#define XPLM_VK_CLEAR 0x0C + +#define XPLM_VK_RETURN 0x0D + +#define XPLM_VK_ESCAPE 0x1B + +#define XPLM_VK_SPACE 0x20 + +#define XPLM_VK_PRIOR 0x21 + +#define XPLM_VK_NEXT 0x22 + +#define XPLM_VK_END 0x23 + +#define XPLM_VK_HOME 0x24 + +#define XPLM_VK_LEFT 0x25 + +#define XPLM_VK_UP 0x26 + +#define XPLM_VK_RIGHT 0x27 + +#define XPLM_VK_DOWN 0x28 + +#define XPLM_VK_SELECT 0x29 + +#define XPLM_VK_PRINT 0x2A + +#define XPLM_VK_EXECUTE 0x2B + +#define XPLM_VK_SNAPSHOT 0x2C + +#define XPLM_VK_INSERT 0x2D + +#define XPLM_VK_DELETE 0x2E + +#define XPLM_VK_HELP 0x2F + +/* XPLM_VK_0 thru XPLM_VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ +#define XPLM_VK_0 0x30 + +#define XPLM_VK_1 0x31 + +#define XPLM_VK_2 0x32 + +#define XPLM_VK_3 0x33 + +#define XPLM_VK_4 0x34 + +#define XPLM_VK_5 0x35 + +#define XPLM_VK_6 0x36 + +#define XPLM_VK_7 0x37 + +#define XPLM_VK_8 0x38 + +#define XPLM_VK_9 0x39 + +/* XPLM_VK_A thru XPLM_VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ +#define XPLM_VK_A 0x41 + +#define XPLM_VK_B 0x42 + +#define XPLM_VK_C 0x43 + +#define XPLM_VK_D 0x44 + +#define XPLM_VK_E 0x45 + +#define XPLM_VK_F 0x46 + +#define XPLM_VK_G 0x47 + +#define XPLM_VK_H 0x48 + +#define XPLM_VK_I 0x49 + +#define XPLM_VK_J 0x4A + +#define XPLM_VK_K 0x4B + +#define XPLM_VK_L 0x4C + +#define XPLM_VK_M 0x4D + +#define XPLM_VK_N 0x4E + +#define XPLM_VK_O 0x4F + +#define XPLM_VK_P 0x50 + +#define XPLM_VK_Q 0x51 + +#define XPLM_VK_R 0x52 + +#define XPLM_VK_S 0x53 + +#define XPLM_VK_T 0x54 + +#define XPLM_VK_U 0x55 + +#define XPLM_VK_V 0x56 + +#define XPLM_VK_W 0x57 + +#define XPLM_VK_X 0x58 + +#define XPLM_VK_Y 0x59 + +#define XPLM_VK_Z 0x5A + +#define XPLM_VK_NUMPAD0 0x60 + +#define XPLM_VK_NUMPAD1 0x61 + +#define XPLM_VK_NUMPAD2 0x62 + +#define XPLM_VK_NUMPAD3 0x63 + +#define XPLM_VK_NUMPAD4 0x64 + +#define XPLM_VK_NUMPAD5 0x65 + +#define XPLM_VK_NUMPAD6 0x66 + +#define XPLM_VK_NUMPAD7 0x67 + +#define XPLM_VK_NUMPAD8 0x68 + +#define XPLM_VK_NUMPAD9 0x69 + +#define XPLM_VK_MULTIPLY 0x6A + +#define XPLM_VK_ADD 0x6B + +#define XPLM_VK_SEPARATOR 0x6C + +#define XPLM_VK_SUBTRACT 0x6D + +#define XPLM_VK_DECIMAL 0x6E + +#define XPLM_VK_DIVIDE 0x6F + +#define XPLM_VK_F1 0x70 + +#define XPLM_VK_F2 0x71 + +#define XPLM_VK_F3 0x72 + +#define XPLM_VK_F4 0x73 + +#define XPLM_VK_F5 0x74 + +#define XPLM_VK_F6 0x75 + +#define XPLM_VK_F7 0x76 + +#define XPLM_VK_F8 0x77 + +#define XPLM_VK_F9 0x78 + +#define XPLM_VK_F10 0x79 + +#define XPLM_VK_F11 0x7A + +#define XPLM_VK_F12 0x7B + +#define XPLM_VK_F13 0x7C + +#define XPLM_VK_F14 0x7D + +#define XPLM_VK_F15 0x7E + +#define XPLM_VK_F16 0x7F + +#define XPLM_VK_F17 0x80 + +#define XPLM_VK_F18 0x81 + +#define XPLM_VK_F19 0x82 + +#define XPLM_VK_F20 0x83 + +#define XPLM_VK_F21 0x84 + +#define XPLM_VK_F22 0x85 + +#define XPLM_VK_F23 0x86 + +#define XPLM_VK_F24 0x87 + +/* The following definitions are extended and are not based on the Microsoft * + * key set. */ +#define XPLM_VK_EQUAL 0xB0 + +#define XPLM_VK_MINUS 0xB1 + +#define XPLM_VK_RBRACE 0xB2 + +#define XPLM_VK_LBRACE 0xB3 + +#define XPLM_VK_QUOTE 0xB4 + +#define XPLM_VK_SEMICOLON 0xB5 + +#define XPLM_VK_BACKSLASH 0xB6 + +#define XPLM_VK_COMMA 0xB7 + +#define XPLM_VK_SLASH 0xB8 + +#define XPLM_VK_PERIOD 0xB9 + +#define XPLM_VK_BACKQUOTE 0xBA + +#define XPLM_VK_ENTER 0xBB + +#define XPLM_VK_NUMPAD_ENT 0xBC + +#define XPLM_VK_NUMPAD_EQ 0xBD + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDisplay.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDisplay.h new file mode 100644 index 0000000..48c7a70 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMDisplay.h @@ -0,0 +1,1477 @@ +#ifndef _XPLMDisplay_h_ +#define _XPLMDisplay_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDisplay + ***************************************************************************/ +/* + * This API provides the basic hooks to draw in X-Plane and create user + * interface. All X-Plane drawing is done in OpenGL. The X-Plane plug-in + * manager takes care of properly setting up the OpenGL context and matrices. + * You do not decide when in your code's execution to draw; X-Plane tells you + * (via callbacks) when it is ready to have your plugin draw. + * + * X-Plane's drawing strategy is straightforward: every "frame" the screen is + * rendered by drawing the 3-D scene (dome, ground, objects, airplanes, etc.) + * and then drawing the cockpit on top of it. Alpha blending is used to + * overlay the cockpit over the world (and the gauges over the panel, etc.). + * X-Plane user interface elements (including windows like the map, the main + * menu, etc.) are then drawn on top of the cockpit. + * + * There are two ways you can draw: directly and in a window. + * + * Direct drawing (deprecated!---more on that below) involves drawing to the + * screen before or after X-Plane finishes a phase of drawing. When you draw + * directly, you can specify whether X-Plane is to complete this phase or not. + * This allows you to do three things: draw before X-Plane does (under it), + * draw after X-Plane does (over it), or draw instead of X-Plane. + * + * To draw directly, you register a callback and specify which phase you want + * to intercept. The plug-in manager will call you over and over to draw that + * phase. + * + * Direct drawing allows you to override scenery, panels, or anything. Note + * that you cannot assume that you are the only plug-in drawing at this phase. + * + * Direct drawing is deprecated; at some point in the X-Plane 11 run, it will + * likely become unsupported entirely as X-Plane transitions from OpenGL to + * modern graphics API backends (e.g., Vulkan, Metal, etc.). In the long term, + * plugins should use the XPLMInstance API for drawing 3-D objects---this will + * be much more efficient than general 3-D OpenGL drawing, and it will + * actually be supported by the new graphics backends. We do not yet know what + * the post-transition API for generic 3-D drawing will look like (if it + * exists at all). + * + * In contrast to direct drawing, window drawing provides a higher level + * functionality. With window drawing, you create a 2-D window that takes up a + * portion of the screen. Window drawing is always two dimensional. Window + * drawing is front-to-back controlled; you can specify that you want your + * window to be brought on top, and other plug-ins may put their window on top + * of you. Window drawing also allows you to sign up for key presses and + * receive mouse clicks. + * + * There are three ways to get keystrokes: + * + * 1. If you create a window, the window can take keyboard focus. It will + * then receive all keystrokes. If no window has focus, X-Plane receives + * keystrokes. Use this to implement typing in dialog boxes, etc. Only + * one window may have focus at a time; your window will be notified if it + * loses focus. + * 2. If you need low level access to the keystroke stream, install a key + * sniffer. Key sniffers can be installed above everything or right in + * front of the sim. + * 3. If you would like to associate key strokes with commands/functions in + * your plug-in, you should simply register a command (via + * XPLMCreateCommand()) and allow users to bind whatever key they choose to + * that command. Another (now deprecated) method of doing so is to use a + * hot key---a key-specific callback. Hotkeys are sent based on virtual + * key strokes, so any key may be distinctly mapped with any modifiers. + * Hot keys can be remapped by other plug-ins. As a plug-in, you don't + * have to worry about what your hot key ends up mapped to; other plug-ins + * may provide a UI for remapping keystrokes. So hotkeys allow a user to + * resolve conflicts and customize keystrokes. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * DRAWING CALLBACKS + ***************************************************************************/ +/* + * Basic drawing callbacks, for low level intercepting of X-Plane's render + * loop. The purpose of drawing callbacks is to provide targeted additions or + * replacements to X-Plane's graphics environment (for example, to add extra + * custom objects, or replace drawing of the AI aircraft). Do not assume that + * the drawing callbacks will be called in the order implied by the + * enumerations. Also do not assume that each drawing phase ends before + * another begins; they may be nested. + * + * Note that all APIs in this section are deprecated, and will likely be + * removed during the X-Plane 11 run as part of the transition to + * Vulkan/Metal/etc. See the XPLMInstance API for future-proof drawing of 3-D + * objects. + * + */ + + +/* + * XPLMDrawingPhase + * + * This constant indicates which part of drawing we are in. Drawing is done + * from the back to the front. We get a callback before or after each item. + * Metaphases provide access to the beginning and end of the 3d (scene) and + * 2d (cockpit) drawing in a manner that is independent of new phases added + * via X-Plane implementation. + * + * **NOTE**: As of XPLM302 the legacy 3D drawing phases (xplm_Phase_FirstScene + * to xplm_Phase_LastScene) are deprecated. When running under X-Plane 11.50 + * with the modern Vulkan or Metal backend, X-Plane will no longer call + * these drawing phases. There is a new drawing phase, xplm_Phase_Modern3D, + * which is supported under OpenGL and Vulkan which is called out roughly + * where the old before xplm_Phase_Airplanes phase was for blending. This + * phase is *NOT* supported under Metal and comes with potentially + * substantial performance overhead. Please do *NOT* opt into this phase if + * you don't do any actual drawing that requires the depth buffer in some + * way! + * + * **WARNING**: As X-Plane's scenery evolves, some drawing phases may cease to + * exist and new ones may be invented. If you need a particularly specific + * use of these codes, consult Austin and/or be prepared to revise your code + * as X-Plane evolves. + * + */ +enum { +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. This is the earliest point at which you can draw * + * in 3-d. */ + xplm_Phase_FirstScene = 0, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing of land and water. */ + xplm_Phase_Terrain = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing runways and other airport detail. */ + xplm_Phase_Airports = 10, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing roads, trails, trains, etc. */ + xplm_Phase_Vectors = 15, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. 3-d objects (houses, smokestacks, etc. */ + xplm_Phase_Objects = 20, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. External views of airplanes, both yours and the * + * AI aircraft. */ + xplm_Phase_Airplanes = 25, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. This is the last point at which you can draw in * + * 3-d. */ + xplm_Phase_LastScene = 30, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM302) + /* A chance to do modern 3D drawing. */ + xplm_Phase_Modern3D = 31, + +#endif /* XPLM302 */ + /* This is the first phase where you can draw in 2-d. */ + xplm_Phase_FirstCockpit = 35, + + /* The non-moving parts of the aircraft panel. */ + xplm_Phase_Panel = 40, + + /* The moving parts of the aircraft panel. */ + xplm_Phase_Gauges = 45, + + /* Floating windows from plugins. */ + xplm_Phase_Window = 50, + + /* The last chance to draw in 2d. */ + xplm_Phase_LastCockpit = 55, + +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMap3D = 100, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMap2D = 101, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMapProfile = 102, + +#endif /* XPLM200 */ + +}; +typedef int XPLMDrawingPhase; + +/* + * XPLMDrawCallback_f + * + * This is the prototype for a low level drawing callback. You are passed in + * the phase and whether it is before or after. If you are before the phase, + * return 1 to let X-Plane draw or 0 to suppress X-Plane drawing. If you are + * after the phase the return value is ignored. + * + * Refcon is a unique value that you specify when registering the callback, + * allowing you to slip a pointer to your own data to the callback. + * + * Upon entry the OpenGL context will be correctly set up for you and OpenGL + * will be in 'local' coordinates for 3d drawing and panel coordinates for 2d + * drawing. The OpenGL state (texturing, etc.) will be unknown. + * + */ +typedef int (* XPLMDrawCallback_f)( + XPLMDrawingPhase inPhase, + int inIsBefore, + void * inRefcon); + +/* + * XPLMRegisterDrawCallback + * + * This routine registers a low level drawing callback. Pass in the phase you + * want to be called for and whether you want to be called before or after. + * This routine returns 1 if the registration was successful, or 0 if the + * phase does not exist in this version of X-Plane. You may register a + * callback multiple times for the same or different phases as long as the + * refcon is unique each time. + * + * Note that this function will likely be removed during the X-Plane 11 run as + * part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + * future-proof drawing of 3-D objects. + * + */ +XPLM_API int XPLMRegisterDrawCallback( + XPLMDrawCallback_f inCallback, + XPLMDrawingPhase inPhase, + int inWantsBefore, + void * inRefcon); + +/* + * XPLMUnregisterDrawCallback + * + * This routine unregisters a draw callback. You must unregister a callback + * for each time you register a callback if you have registered it multiple + * times with different refcons. The routine returns 1 if it can find the + * callback to unregister, 0 otherwise. + * + * Note that this function will likely be removed during the X-Plane 11 run as + * part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + * future-proof drawing of 3-D objects. + * + */ +XPLM_API int XPLMUnregisterDrawCallback( + XPLMDrawCallback_f inCallback, + XPLMDrawingPhase inPhase, + int inWantsBefore, + void * inRefcon); + +/*************************************************************************** + * WINDOW API + ***************************************************************************/ +/* + * The window API provides a high-level abstraction for drawing with UI + * interaction. + * + * Windows may operate in one of two modes: legacy (for plugins compiled + * against old versions of the XPLM, as well as windows created via the + * deprecated XPLMCreateWindow() function, rather than XPLMCreateWindowEx()), + * or modern (for windows compiled against the XPLM300 or newer API, and + * created via XPLMCreateWindowEx()). + * + * Modern windows have access to new X-Plane 11 windowing features, like + * support for new positioning modes (including being "popped out" into their + * own first-class window in the operating system). They can also optionally + * be decorated in the style of X-Plane 11 windows (like the map). + * + * Modern windows operate in "boxel" units. A boxel ("box of pixels") is a + * unit of virtual pixels which, depending on X-Plane's scaling, may + * correspond to an arbitrary NxN "box" of real pixels on screen. Because + * X-Plane handles this scaling automatically, you can effectively treat the + * units as though you were simply drawing in pixels, and know that when + * X-Plane is running with 150% or 200% scaling, your drawing will be + * automatically scaled (and likewise all mouse coordinates, screen bounds, + * etc. will also be auto-scaled). + * + * In contrast, legacy windows draw in true screen pixels, and thus tend to + * look quite small when X-Plane is operating in a scaled mode. + * + * Legacy windows have their origin in the lower left of the main X-Plane + * window. In contrast, since modern windows are not constrained to the main + * window, they have their origin in the lower left of the entire global + * desktop space, and the lower left of the main X-Plane window is not + * guaranteed to be (0, 0). In both cases, x increases as you move left, and y + * increases as you move up. + * + */ + + +/* + * XPLMWindowID + * + * This is an opaque identifier for a window. You use it to control your + * window. When you create a window (via either XPLMCreateWindow() or + * XPLMCreateWindowEx()), you will specify callbacks to handle drawing, mouse + * interaction, etc. + * + */ +typedef void * XPLMWindowID; + +/* + * XPLMDrawWindow_f + * + * A callback to handle 2-D drawing of your window. You are passed in your + * window and its refcon. Draw the window. You can use other XPLM functions + * from this header to find the current dimensions of your window, etc. When + * this callback is called, the OpenGL context will be set properly for 2-D + * window drawing. + * + * **Note**: Because you are drawing your window over a background, you can + * make a translucent window easily by simply not filling in your entire + * window's bounds. + * + */ +typedef void (* XPLMDrawWindow_f)( + XPLMWindowID inWindowID, + void * inRefcon); + +/* + * XPLMHandleKey_f + * + * This function is called when a key is pressed or keyboard focus is taken + * away from your window. If losingFocus is 1, you are losing the keyboard + * focus, otherwise a key was pressed and inKey contains its character. You + * are also passed your window and a refcon. + * + * Warning: this API declares virtual keys as a signed character; however the + * VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + * (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + * to an unsigned char to get correct comparisons in C. + * + */ +typedef void (* XPLMHandleKey_f)( + XPLMWindowID inWindowID, + char inKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefcon, + int losingFocus); + +/* + * XPLMMouseStatus + * + * When the mouse is clicked, your mouse click routine is called repeatedly. + * It is first called with the mouse down message. It is then called zero or + * more times with the mouse-drag message, and finally it is called once with + * the mouse up message. All of these messages will be directed to the same + * window; you are guaranteed to not receive a drag or mouse-up event without + * first receiving the corresponding mouse-down. + * + */ +enum { + xplm_MouseDown = 1, + + xplm_MouseDrag = 2, + + xplm_MouseUp = 3, + + +}; +typedef int XPLMMouseStatus; + +/* + * XPLMHandleMouseClick_f + * + * You receive this call for one of three events: + * + * - when the user clicks the mouse button down + * - (optionally) when the user drags the mouse after a down-click, but before + * the up-click + * - when the user releases the down-clicked mouse button. + * + * You receive the x and y of the click, your window, and a refcon. Return 1 + * to consume the click, or 0 to pass it through. + * + * WARNING: passing clicks through windows (as of this writing) causes mouse + * tracking problems in X-Plane; do not use this feature! + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef int (* XPLMHandleMouseClick_f)( + XPLMWindowID inWindowID, + int x, + int y, + XPLMMouseStatus inMouse, + void * inRefcon); + +#if defined(XPLM200) +/* + * XPLMCursorStatus + * + * XPLMCursorStatus describes how you would like X-Plane to manage the cursor. + * See XPLMHandleCursor_f for more info. + * + */ +enum { + /* X-Plane manages the cursor normally, plugin does not affect the cusrsor. */ + xplm_CursorDefault = 0, + + /* X-Plane hides the cursor. */ + xplm_CursorHidden = 1, + + /* X-Plane shows the cursor as the default arrow. */ + xplm_CursorArrow = 2, + + /* X-Plane shows the cursor but lets you select an OS cursor. */ + xplm_CursorCustom = 3, + + +}; +typedef int XPLMCursorStatus; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMHandleCursor_f + * + * The SDK calls your cursor status callback when the mouse is over your + * plugin window. Return a cursor status code to indicate how you would like + * X-Plane to manage the cursor. If you return xplm_CursorDefault, the SDK + * will try lower-Z-order plugin windows, then let the sim manage the cursor. + * + * Note: you should never show or hide the cursor yourself---these APIs are + * typically reference-counted and thus cannot safely and predictably be used + * by the SDK. Instead return one of xplm_CursorHidden to hide the cursor or + * xplm_CursorArrow/xplm_CursorCustom to show the cursor. + * + * If you want to implement a custom cursor by drawing a cursor in OpenGL, use + * xplm_CursorHidden to hide the OS cursor and draw the cursor using a 2-d + * drawing callback (after xplm_Phase_Window is probably a good choice, but + * see deprecation warnings on the drawing APIs!). If you want to use a + * custom OS-based cursor, use xplm_CursorCustom to ask X-Plane to show the + * cursor but not affect its image. You can then use an OS specific call like + * SetThemeCursor (Mac) or SetCursor/LoadCursor (Windows). + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef XPLMCursorStatus (* XPLMHandleCursor_f)( + XPLMWindowID inWindowID, + int x, + int y, + void * inRefcon); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMHandleMouseWheel_f + * + * The SDK calls your mouse wheel callback when one of the mouse wheels is + * scrolled within your window. Return 1 to consume the mouse wheel movement + * or 0 to pass them on to a lower window. (If your window appears opaque to + * the user, you should consume mouse wheel scrolling even if it does + * nothing.) The number of "clicks" indicates how far the wheel was turned + * since the last callback. The wheel is 0 for the vertical axis or 1 for the + * horizontal axis (for OS/mouse combinations that support this). + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef int (* XPLMHandleMouseWheel_f)( + XPLMWindowID inWindowID, + int x, + int y, + int wheel, + int clicks, + void * inRefcon); +#endif /* XPLM200 */ + +#if defined(XPLM300) +/* + * XPLMWindowLayer + * + * XPLMWindowLayer describes where in the ordering of windows X-Plane should + * place a particular window. Windows in higher layers cover windows in lower + * layers. So, a given window might be at the top of its particular layer, but + * it might still be obscured by a window in a higher layer. (This happens + * frequently when floating windows, like X-Plane's map, are covered by a + * modal alert.) + * + * Your window's layer can only be specified when you create the window (in + * the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). For this reason, + * layering only applies to windows created with new X-Plane 11 GUI features. + * (Windows created using the older XPLMCreateWindow(), or windows compiled + * against a pre-XPLM300 version of the SDK will simply be placed in the + * flight overlay window layer.) + * + */ +enum { + /* The lowest layer, used for HUD-like displays while flying. */ + xplm_WindowLayerFlightOverlay = 0, + + /* Windows that "float" over the sim, like the X-Plane 11 map does. If you are* + * not sure which layer to create your window in, choose floating. */ + xplm_WindowLayerFloatingWindows = 1, + + /* An interruptive modal that covers the sim with a transparent black overlay * + * to draw the user's focus to the alert */ + xplm_WindowLayerModal = 2, + + /* "Growl"-style notifications that are visible in a corner of the screen, * + * even over modals */ + xplm_WindowLayerGrowlNotifications = 3, + + +}; +typedef int XPLMWindowLayer; +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMWindowDecoration + * + * XPLMWindowDecoration describes how "modern" windows will be displayed. This + * impacts both how X-Plane draws your window as well as certain mouse + * handlers. + * + * Your window's decoration can only be specified when you create the window + * (in the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). + * + */ +enum { + /* X-Plane will draw no decoration for your window, and apply no automatic * + * click handlers. The window will not stop click from passing through its * + * bounds. This is suitable for "windows" which request, say, the full screen * + * bounds, then only draw in a small portion of the available area. */ + xplm_WindowDecorationNone = 0, + + /* The default decoration for "native" windows, like the map. Provides a solid* + * background, as well as click handlers for resizing and dragging the window.*/ + xplm_WindowDecorationRoundRectangle = 1, + + /* X-Plane will draw no decoration for your window, nor will it provide resize* + * handlers for your window edges, but it will stop clicks from passing * + * through your windows bounds. */ + xplm_WindowDecorationSelfDecorated = 2, + + /* Like self-decorated, but with resizing; X-Plane will draw no decoration for* + * your window, but it will stop clicks from passing through your windows * + * bounds, and provide automatic mouse handlers for resizing. */ + xplm_WindowDecorationSelfDecoratedResizable = 3, + + +}; +typedef int XPLMWindowDecoration; +#endif /* XPLM301 */ + +#if defined(XPLM200) +/* + * XPLMCreateWindow_t + * + * The XPMCreateWindow_t structure defines all of the parameters used to + * create a modern window using XPLMCreateWindowEx(). The structure will be + * expanded in future SDK APIs to include more features. Always set the + * structSize member to the size of your struct in bytes! + * + * All windows created by this function in the XPLM300 version of the API are + * created with the new X-Plane 11 GUI features. This means your plugin will + * get to "know" about the existence of X-Plane windows other than the main + * window. All drawing and mouse callbacks for your window will occur in + * "boxels," giving your windows automatic support for high-DPI scaling in + * X-Plane. In addition, your windows can opt-in to decoration with the + * X-Plane 11 window styling, and you can use the + * XPLMSetWindowPositioningMode() API to make your window "popped out" into a + * first-class operating system window. + * + * Note that this requires dealing with your window's bounds in "global + * desktop" positioning units, rather than the traditional panel coordinate + * system. In global desktop coordinates, the main X-Plane window may not have + * its origin at coordinate (0, 0), and your own window may have negative + * coordinates. Assuming you don't implicitly assume (0, 0) as your origin, + * the only API change you should need is to start using + * XPLMGetMouseLocationGlobal() rather than XPLMGetMouseLocation(), and + * XPLMGetScreenBoundsGlobal() instead of XPLMGetScreenSize(). + * + * If you ask to be decorated as a floating window, you'll get the blue window + * control bar and blue backing that you see in X-Plane 11's normal "floating" + * windows (like the map). + * + */ +typedef struct { + /* Used to inform XPLMCreateWindowEx() of the SDK version you compiled * + * against; should always be set to sizeof(XPLMCreateWindow_t) */ + int structSize; + /* Left bound, in global desktop boxels */ + int left; + /* Top bound, in global desktop boxels */ + int top; + /* Right bound, in global desktop boxels */ + int right; + /* Bottom bound, in global desktop boxels */ + int bottom; + int visible; + XPLMDrawWindow_f drawWindowFunc; + /* A callback to handle the user left-clicking within your window (or NULL to * + * ignore left clicks) */ + XPLMHandleMouseClick_f handleMouseClickFunc; + XPLMHandleKey_f handleKeyFunc; + XPLMHandleCursor_f handleCursorFunc; + XPLMHandleMouseWheel_f handleMouseWheelFunc; + /* A reference which will be passed into each of your window callbacks. Use * + * this to pass information to yourself as needed. */ + void * refcon; +#if defined(XPLM301) + /* Specifies the type of X-Plane 11-style "wrapper" you want around your * + * window, if any */ + XPLMWindowDecoration decorateAsFloatingWindow; +#endif /* XPLM301 */ +#if defined(XPLM300) + XPLMWindowLayer layer; +#endif /* XPLM300 */ +#if defined(XPLM300) + /* A callback to handle the user right-clicking within your window (or NULL to* + * ignore right clicks) */ + XPLMHandleMouseClick_f handleRightClickFunc; +#endif /* XPLM300 */ +} XPLMCreateWindow_t; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMCreateWindowEx + * + * This routine creates a new "modern" window. You pass in an + * XPLMCreateWindow_t structure with all of the fields set in. You must set + * the structSize of the structure to the size of the actual structure you + * used. Also, you must provide functions for every callback---you may not + * leave them null! (If you do not support the cursor or mouse wheel, use + * functions that return the default values.) + * + */ +XPLM_API XPLMWindowID XPLMCreateWindowEx( + XPLMCreateWindow_t * inParams); +#endif /* XPLM200 */ + +/* + * XPLMCreateWindow + * + * Deprecated as of XPLM300. + * + * This routine creates a new legacy window. Unlike modern windows (created + * via XPLMCreateWindowEx()), legacy windows do not have access to X-Plane 11 + * features like automatic scaling for high-DPI screens, native window styles, + * or support for being "popped out" into first-class operating system + * windows. + * + * Pass in the dimensions and offsets to the window's bottom left corner from + * the bottom left of the screen. You can specify whether the window is + * initially visible or not. Also, you pass in three callbacks to run the + * window and a refcon. This function returns a window ID you can use to + * refer to the new window. + * + * NOTE: Legacy windows do not have "frames"; you are responsible for drawing + * the background and frame of the window. Higher level libraries have + * routines which make this easy. + * + */ +XPLM_API XPLMWindowID XPLMCreateWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible, + XPLMDrawWindow_f inDrawCallback, + XPLMHandleKey_f inKeyCallback, + XPLMHandleMouseClick_f inMouseCallback, + void * inRefcon); + +/* + * XPLMDestroyWindow + * + * This routine destroys a window. The window's callbacks are not called + * after this call. Keyboard focus is removed from the window before + * destroying it. + * + */ +XPLM_API void XPLMDestroyWindow( + XPLMWindowID inWindowID); + +/* + * XPLMGetScreenSize + * + * This routine returns the size of the main X-Plane OpenGL window in pixels. + * This number can be used to get a rough idea of the amount of detail the + * user will be able to see when drawing in 3-d. + * + */ +XPLM_API void XPLMGetScreenSize( + int * outWidth, /* Can be NULL */ + int * outHeight); /* Can be NULL */ + +#if defined(XPLM300) +/* + * XPLMGetScreenBoundsGlobal + * + * This routine returns the bounds of the "global" X-Plane desktop, in boxels. + * Unlike the non-global version XPLMGetScreenSize(), this is multi-monitor + * aware. There are three primary consequences of multimonitor awareness. + * + * First, if the user is running X-Plane in full-screen on two or more + * monitors (typically configured using one full-screen window per monitor), + * the global desktop will be sized to include all X-Plane windows. + * + * Second, the origin of the screen coordinates is not guaranteed to be (0, + * 0). Suppose the user has two displays side-by-side, both running at 1080p. + * Suppose further that they've configured their OS to make the left display + * their "primary" monitor, and that X-Plane is running in full-screen on + * their right monitor only. In this case, the global desktop bounds would be + * the rectangle from (1920, 0) to (3840, 1080). If the user later asked + * X-Plane to draw on their primary monitor as well, the bounds would change + * to (0, 0) to (3840, 1080). + * + * Finally, if the usable area of the virtual desktop is not a perfect + * rectangle (for instance, because the monitors have different resolutions or + * because one monitor is configured in the operating system to be above and + * to the right of the other), the global desktop will include any wasted + * space. Thus, if you have two 1080p monitors, and monitor 2 is configured to + * have its bottom left touch monitor 1's upper right, your global desktop + * area would be the rectangle from (0, 0) to (3840, 2160). + * + * Note that popped-out windows (windows drawn in their own operating system + * windows, rather than "floating" within X-Plane) are not included in these + * bounds. + * + */ +XPLM_API void XPLMGetScreenBoundsGlobal( + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMReceiveMonitorBoundsGlobal_f + * + * This function is informed of the global bounds (in boxels) of a particular + * monitor within the X-Plane global desktop space. Note that X-Plane must be + * running in full screen on a monitor in order for that monitor to be passed + * to you in this callback. + * + */ +typedef void (* XPLMReceiveMonitorBoundsGlobal_f)( + int inMonitorIndex, + int inLeftBx, + int inTopBx, + int inRightBx, + int inBottomBx, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMGetAllMonitorBoundsGlobal + * + * This routine immediately calls you back with the bounds (in boxels) of each + * full-screen X-Plane window within the X-Plane global desktop space. Note + * that if a monitor is *not* covered by an X-Plane window, you cannot get its + * bounds this way. Likewise, monitors with only an X-Plane window (not in + * full-screen mode) will not be included. + * + * If X-Plane is running in full-screen and your monitors are of the same size + * and configured contiguously in the OS, then the combined global bounds of + * all full-screen monitors will match the total global desktop bounds, as + * returned by XPLMGetScreenBoundsGlobal(). (Of course, if X-Plane is running + * in windowed mode, this will not be the case. Likewise, if you have + * differently sized monitors, the global desktop space will include wasted + * space.) + * + * Note that this function's monitor indices match those provided by + * XPLMGetAllMonitorBoundsOS(), but the coordinates are different (since the + * X-Plane global desktop may not match the operating system's global desktop, + * and one X-Plane boxel may be larger than one pixel due to 150% or 200% + * scaling). + * + */ +XPLM_API void XPLMGetAllMonitorBoundsGlobal( + XPLMReceiveMonitorBoundsGlobal_f inMonitorBoundsCallback, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMReceiveMonitorBoundsOS_f + * + * This function is informed of the global bounds (in pixels) of a particular + * monitor within the operating system's global desktop space. Note that a + * monitor index being passed to you here does not indicate that X-Plane is + * running in full screen on this monitor, or even that any X-Plane windows + * exist on this monitor. + * + */ +typedef void (* XPLMReceiveMonitorBoundsOS_f)( + int inMonitorIndex, + int inLeftPx, + int inTopPx, + int inRightPx, + int inBottomPx, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMGetAllMonitorBoundsOS + * + * This routine immediately calls you back with the bounds (in pixels) of each + * monitor within the operating system's global desktop space. Note that + * unlike XPLMGetAllMonitorBoundsGlobal(), this may include monitors that have + * no X-Plane window on them. + * + * Note that this function's monitor indices match those provided by + * XPLMGetAllMonitorBoundsGlobal(), but the coordinates are different (since + * the X-Plane global desktop may not match the operating system's global + * desktop, and one X-Plane boxel may be larger than one pixel). + * + */ +XPLM_API void XPLMGetAllMonitorBoundsOS( + XPLMReceiveMonitorBoundsOS_f inMonitorBoundsCallback, + void * inRefcon); +#endif /* XPLM300 */ + +/* + * XPLMGetMouseLocation + * + * Deprecated in XPLM300. Modern windows should use + * XPLMGetMouseLocationGlobal() instead. + * + * This routine returns the current mouse location in pixels relative to the + * main X-Plane window. The bottom left corner of the main window is (0, 0). + * Pass NULL to not receive info about either parameter. + * + * Because this function gives the mouse position relative to the main X-Plane + * window (rather than in global bounds), this function should only be used by + * legacy windows. Modern windows should instead get the mouse position in + * global desktop coordinates using XPLMGetMouseLocationGlobal(). + * + * Note that unlike XPLMGetMouseLocationGlobal(), if the mouse goes outside + * the user's main monitor (for instance, to a pop out window or a secondary + * monitor), this function will not reflect it. + * + */ +XPLM_API void XPLMGetMouseLocation( + int * outX, /* Can be NULL */ + int * outY); /* Can be NULL */ + +#if defined(XPLM300) +/* + * XPLMGetMouseLocationGlobal + * + * Returns the current mouse location in global desktop boxels. Unlike + * XPLMGetMouseLocation(), the bottom left of the main X-Plane window is not + * guaranteed to be (0, 0)---instead, the origin is the lower left of the + * entire global desktop space. In addition, this routine gives the real mouse + * location when the mouse goes to X-Plane windows other than the primary + * display. Thus, it can be used with both pop-out windows and secondary + * monitors. + * + * This is the mouse location function to use with modern windows (i.e., those + * created by XPLMCreateWindowEx()). + * + * Pass NULL to not receive info about either parameter. + * + */ +XPLM_API void XPLMGetMouseLocationGlobal( + int * outX, /* Can be NULL */ + int * outY); /* Can be NULL */ +#endif /* XPLM300 */ + +/* + * XPLMGetWindowGeometry + * + * This routine returns the position and size of a window. The units and + * coordinate system vary depending on the type of window you have. + * + * If this is a legacy window (one compiled against a pre-XPLM300 version of + * the SDK, or an XPLM300 window that was not created using + * XPLMCreateWindowEx()), the units are pixels relative to the main X-Plane + * display. + * + * If, on the other hand, this is a new X-Plane 11-style window (compiled + * against the XPLM300 SDK and created using XPLMCreateWindowEx()), the units + * are global desktop boxels. + * + * Pass NULL to not receive any paramter. + * + */ +XPLM_API void XPLMGetWindowGeometry( + XPLMWindowID inWindowID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/* + * XPLMSetWindowGeometry + * + * This routine allows you to set the position and size of a window. + * + * The units and coordinate system match those of XPLMGetWindowGeometry(). + * That is, modern windows use global desktop boxel coordinates, while legacy + * windows use pixels relative to the main X-Plane display. + * + * Note that this only applies to "floating" windows (that is, windows that + * are drawn within the X-Plane simulation windows, rather than being "popped + * out" into their own first-class operating system windows). To set the + * position of windows whose positioning mode is xplm_WindowPopOut, you'll + * need to instead use XPLMSetWindowGeometryOS(). + * + */ +XPLM_API void XPLMSetWindowGeometry( + XPLMWindowID inWindowID, + int inLeft, + int inTop, + int inRight, + int inBottom); + +#if defined(XPLM300) +/* + * XPLMGetWindowGeometryOS + * + * This routine returns the position and size of a "popped out" window (i.e., + * a window whose positioning mode is xplm_WindowPopOut), in operating system + * pixels. Pass NULL to not receive any parameter. + * + */ +XPLM_API void XPLMGetWindowGeometryOS( + XPLMWindowID inWindowID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowGeometryOS + * + * This routine allows you to set the position and size, in operating system + * pixel coordinates, of a popped out window (that is, a window whose + * positioning mode is xplm_WindowPopOut, which exists outside the X-Plane + * simulation window, in its own first-class operating system window). + * + * Note that you are responsible for ensuring both that your window is popped + * out (using XPLMWindowIsPoppedOut()) and that a monitor really exists at the + * OS coordinates you provide (using XPLMGetAllMonitorBoundsOS()). + * + */ +XPLM_API void XPLMSetWindowGeometryOS( + XPLMWindowID inWindowID, + int inLeft, + int inTop, + int inRight, + int inBottom); +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMGetWindowGeometryVR + * + * Returns the width and height, in boxels, of a window in VR. Note that you + * are responsible for ensuring your window is in VR (using + * XPLMWindowIsInVR()). + * + */ +XPLM_API void XPLMGetWindowGeometryVR( + XPLMWindowID inWindowID, + int * outWidthBoxels, /* Can be NULL */ + int * outHeightBoxels); /* Can be NULL */ +#endif /* XPLM301 */ + +#if defined(XPLM301) +/* + * XPLMSetWindowGeometryVR + * + * This routine allows you to set the size, in boxels, of a window in VR (that + * is, a window whose positioning mode is xplm_WindowVR). + * + * Note that you are responsible for ensuring your window is in VR (using + * XPLMWindowIsInVR()). + * + */ +XPLM_API void XPLMSetWindowGeometryVR( + XPLMWindowID inWindowID, + int widthBoxels, + int heightBoxels); +#endif /* XPLM301 */ + +/* + * XPLMGetWindowIsVisible + * + * Returns true (1) if the specified window is visible. + * + */ +XPLM_API int XPLMGetWindowIsVisible( + XPLMWindowID inWindowID); + +/* + * XPLMSetWindowIsVisible + * + * This routine shows or hides a window. + * + */ +XPLM_API void XPLMSetWindowIsVisible( + XPLMWindowID inWindowID, + int inIsVisible); + +#if defined(XPLM300) +/* + * XPLMWindowIsPoppedOut + * + * True if this window has been popped out (making it a first-class window in + * the operating system), which in turn is true if and only if you have set + * the window's positioning mode to xplm_WindowPopOut. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK cannot be popped out.) + * + */ +XPLM_API int XPLMWindowIsPoppedOut( + XPLMWindowID inWindowID); +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMWindowIsInVR + * + * True if this window has been moved to the virtual reality (VR) headset, + * which in turn is true if and only if you have set the window's positioning + * mode to xplm_WindowVR. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM301 version of + * the SDK cannot be moved to VR.) + * + */ +XPLM_API int XPLMWindowIsInVR( + XPLMWindowID inWindowID); +#endif /* XPLM301 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowGravity + * + * A window's "gravity" controls how the window shifts as the whole X-Plane + * window resizes. A gravity of 1 means the window maintains its positioning + * relative to the right or top edges, 0 the left/bottom, and 0.5 keeps it + * centered. + * + * Default gravity is (0, 1, 0, 1), meaning your window will maintain its + * position relative to the top left and will not change size as its + * containing window grows. + * + * If you wanted, say, a window that sticks to the top of the screen (with a + * constant height), but which grows to take the full width of the window, you + * would pass (0, 1, 1, 1). Because your left and right edges would maintain + * their positioning relative to their respective edges of the screen, the + * whole width of your window would change with the X-Plane window. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will simply get the default gravity.) + * + */ +XPLM_API void XPLMSetWindowGravity( + XPLMWindowID inWindowID, + float inLeftGravity, + float inTopGravity, + float inRightGravity, + float inBottomGravity); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowResizingLimits + * + * Sets the minimum and maximum size of the client rectangle of the given + * window. (That is, it does not include any window styling that you might + * have asked X-Plane to apply on your behalf.) All resizing operations are + * constrained to these sizes. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will have no minimum or maximum size.) + * + */ +XPLM_API void XPLMSetWindowResizingLimits( + XPLMWindowID inWindowID, + int inMinWidthBoxels, + int inMinHeightBoxels, + int inMaxWidthBoxels, + int inMaxHeightBoxels); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMWindowPositioningMode + * + * XPLMWindowPositionMode describes how X-Plane will position your window on + * the user's screen. X-Plane will maintain this positioning mode even as the + * user resizes their window or adds/removes full-screen monitors. + * + * Positioning mode can only be set for "modern" windows (that is, windows + * created using XPLMCreateWindowEx() and compiled against the XPLM300 SDK). + * Windows created using the deprecated XPLMCreateWindow(), or windows + * compiled against a pre-XPLM300 version of the SDK will simply get the + * "free" positioning mode. + * + */ +enum { + /* The default positioning mode. Set the window geometry and its future * + * position will be determined by its window gravity, resizing limits, and * + * user interactions. */ + xplm_WindowPositionFree = 0, + + /* Keep the window centered on the monitor you specify */ + xplm_WindowCenterOnMonitor = 1, + + /* Keep the window full screen on the monitor you specify */ + xplm_WindowFullScreenOnMonitor = 2, + + /* Like gui_window_full_screen_on_monitor, but stretches over *all* monitors * + * and popout windows. This is an obscure one... unless you have a very good * + * reason to need it, you probably don't! */ + xplm_WindowFullScreenOnAllMonitors = 3, + + /* A first-class window in the operating system, completely separate from the * + * X-Plane window(s) */ + xplm_WindowPopOut = 4, + +#if defined(XPLM301) + /* A floating window visible on the VR headset */ + xplm_WindowVR = 5, + +#endif /* XPLM301 */ + +}; +typedef int XPLMWindowPositioningMode; +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowPositioningMode + * + * Sets the policy for how X-Plane will position your window. + * + * Some positioning modes apply to a particular monitor. For those modes, you + * can pass a negative monitor index to position the window on the main + * X-Plane monitor (the screen with the X-Plane menu bar at the top). Or, if + * you have a specific monitor you want to position your window on, you can + * pass a real monitor index as received from, e.g., + * XPLMGetAllMonitorBoundsOS(). + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will always use xplm_WindowPositionFree.) + * + */ +XPLM_API void XPLMSetWindowPositioningMode( + XPLMWindowID inWindowID, + XPLMWindowPositioningMode inPositioningMode, + int inMonitorIndex); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowTitle + * + * Sets the name for a window. This only applies to windows that opted-in to + * styling as an X-Plane 11 floating window (i.e., with styling mode + * xplm_WindowDecorationRoundRectangle) when they were created using + * XPLMCreateWindowEx(). + * + */ +XPLM_API void XPLMSetWindowTitle( + XPLMWindowID inWindowID, + const char * inWindowTitle); +#endif /* XPLM300 */ + +/* + * XPLMGetWindowRefCon + * + * Returns a window's reference constant, the unique value you can use for + * your own purposes. + * + */ +XPLM_API void * XPLMGetWindowRefCon( + XPLMWindowID inWindowID); + +/* + * XPLMSetWindowRefCon + * + * Sets a window's reference constant. Use this to pass data to yourself in + * the callbacks. + * + */ +XPLM_API void XPLMSetWindowRefCon( + XPLMWindowID inWindowID, + void * inRefcon); + +/* + * XPLMTakeKeyboardFocus + * + * This routine gives a specific window keyboard focus. Keystrokes will be + * sent to that window. Pass a window ID of 0 to remove keyboard focus from + * any plugin-created windows and instead pass keyboard strokes directly to + * X-Plane. + * + */ +XPLM_API void XPLMTakeKeyboardFocus( + XPLMWindowID inWindow); + +/* + * XPLMHasKeyboardFocus + * + * Returns true (1) if the indicated window has keyboard focus. Pass a window + * ID of 0 to see if no plugin window has focus, and all keystrokes will go + * directly to X-Plane. + * + */ +XPLM_API int XPLMHasKeyboardFocus( + XPLMWindowID inWindow); + +/* + * XPLMBringWindowToFront + * + * This routine brings the window to the front of the Z-order for its layer. + * Windows are brought to the front automatically when they are created. + * Beyond that, you should make sure you are front before handling mouse + * clicks. + * + * Note that this only brings your window to the front of its layer + * (XPLMWindowLayer). Thus, if you have a window in the floating window layer + * (xplm_WindowLayerFloatingWindows), but there is a modal window (in layer + * xplm_WindowLayerModal) above you, you would still not be the true frontmost + * window after calling this. (After all, the window layers are strictly + * ordered, and no window in a lower layer can ever be above any window in a + * higher one.) + * + */ +XPLM_API void XPLMBringWindowToFront( + XPLMWindowID inWindow); + +/* + * XPLMIsWindowInFront + * + * This routine returns true if the window you passed in is the frontmost + * visible window in its layer (XPLMWindowLayer). + * + * Thus, if you have a window at the front of the floating window layer + * (xplm_WindowLayerFloatingWindows), this will return true even if there is a + * modal window (in layer xplm_WindowLayerModal) above you. (Not to worry, + * though: in such a case, X-Plane will not pass clicks or keyboard input down + * to your layer until the window above stops "eating" the input.) + * + * Note that legacy windows are always placed in layer + * xplm_WindowLayerFlightOverlay, while modern-style windows default to + * xplm_WindowLayerFloatingWindows. This means it's perfectly consistent to + * have two different plugin-created windows (one legacy, one modern) *both* + * be in the front (of their different layers!) at the same time. + * + */ +XPLM_API int XPLMIsWindowInFront( + XPLMWindowID inWindow); + +/*************************************************************************** + * KEY SNIFFERS + ***************************************************************************/ +/* + * Low-level keyboard handlers. Allows for intercepting keystrokes outside the + * normal rules of the user interface. + * + */ + + +/* + * XPLMKeySniffer_f + * + * This is the prototype for a low level key-sniffing function. Window-based + * UI _should not use this_! The windowing system provides high-level + * mediated keyboard access, via the callbacks you attach to your + * XPLMCreateWindow_t. By comparison, the key sniffer provides low level + * keyboard access. + * + * Key sniffers are provided to allow libraries to provide non-windowed user + * interaction. For example, the MUI library uses a key sniffer to do pop-up + * text entry. + * + * Return 1 to pass the key on to the next sniffer, the window manager, + * X-Plane, or whomever is down stream. Return 0 to consume the key. + * + * Warning: this API declares virtual keys as a signed character; however the + * VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + * (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + * to an unsigned char to get correct comparisons in C. + * + */ +typedef int (* XPLMKeySniffer_f)( + char inChar, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefcon); + +/* + * XPLMRegisterKeySniffer + * + * This routine registers a key sniffing callback. You specify whether you + * want to sniff before the window system, or only sniff keys the window + * system does not consume. You should ALMOST ALWAYS sniff non-control keys + * after the window system. When the window system consumes a key, it is + * because the user has "focused" a window. Consuming the key or taking + * action based on the key will produce very weird results. Returns + * 1 if successful. + * + */ +XPLM_API int XPLMRegisterKeySniffer( + XPLMKeySniffer_f inCallback, + int inBeforeWindows, + void * inRefcon); + +/* + * XPLMUnregisterKeySniffer + * + * This routine unregisters a key sniffer. You must unregister a key sniffer + * for every time you register one with the exact same signature. Returns 1 + * if successful. + * + */ +XPLM_API int XPLMUnregisterKeySniffer( + XPLMKeySniffer_f inCallback, + int inBeforeWindows, + void * inRefcon); + +/*************************************************************************** + * HOT KEYS + ***************************************************************************/ +/* + * Keystrokes that can be managed by others. These are lower-level than window + * keyboard handlers (i.e., callbacks you attach to your XPLMCreateWindow_t), + * but higher level than key sniffers. + * + */ + + +/* + * XPLMHotKey_f + * + * Your hot key callback simply takes a pointer of your choosing. + * + */ +typedef void (* XPLMHotKey_f)( + void * inRefcon); + +/* + * XPLMHotKeyID + * + * An opaque ID used to identify a hot key. + * + */ +typedef void * XPLMHotKeyID; + +/* + * XPLMRegisterHotKey + * + * This routine registers a hot key. You specify your preferred key stroke + * virtual key/flag combination, a description of what your callback does (so + * other plug-ins can describe the plug-in to the user for remapping) and a + * callback function and opaque pointer to pass in). A new hot key ID is + * returned. During execution, the actual key associated with your hot key + * may change, but you are insulated from this. + * + */ +XPLM_API XPLMHotKeyID XPLMRegisterHotKey( + char inVirtualKey, + XPLMKeyFlags inFlags, + const char * inDescription, + XPLMHotKey_f inCallback, + void * inRefcon); + +/* + * XPLMUnregisterHotKey + * + * Unregisters a hot key. You can only unregister your own hot keys. + * + */ +XPLM_API void XPLMUnregisterHotKey( + XPLMHotKeyID inHotKey); + +/* + * XPLMCountHotKeys + * + * Returns the number of current hot keys. + * + */ +XPLM_API int XPLMCountHotKeys(void); + +/* + * XPLMGetNthHotKey + * + * Returns a hot key by index, for iteration on all hot keys. + * + */ +XPLM_API XPLMHotKeyID XPLMGetNthHotKey( + int inIndex); + +/* + * XPLMGetHotKeyInfo + * + * Returns information about the hot key. Return NULL for any parameter you + * don't want info about. The description should be at least 512 chars long. + * + */ +XPLM_API void XPLMGetHotKeyInfo( + XPLMHotKeyID inHotKey, + char * outVirtualKey, /* Can be NULL */ + XPLMKeyFlags * outFlags, /* Can be NULL */ + char * outDescription, /* Can be NULL */ + XPLMPluginID * outPlugin); /* Can be NULL */ + +/* + * XPLMSetHotKeyCombination + * + * Remaps a hot key's keystrokes. You may remap another plugin's keystrokes. + * + */ +XPLM_API void XPLMSetHotKeyCombination( + XPLMHotKeyID inHotKey, + char inVirtualKey, + XPLMKeyFlags inFlags); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMGraphics.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMGraphics.h new file mode 100644 index 0000000..d7aef52 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMGraphics.h @@ -0,0 +1,437 @@ +#ifndef _XPLMGraphics_h_ +#define _XPLMGraphics_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMGraphics + ***************************************************************************/ +/* + * A few notes on coordinate systems: + * + * X-Plane uses three kinds of coordinates. Global coordinates are specified + * as latitude, longitude and elevation. This coordinate system never changes + * but is not very precise. + * + * OpenGL (or 'local') coordinates are cartesian and shift with the plane. + * They offer more precision and are used for 3-d OpenGL drawing. The X axis + * is aligned east-west with positive X meaning east. The Y axis is aligned + * straight up and down at the point 0,0,0 (but since the earth is round it is + * not truly straight up and down at other points). The Z axis is aligned + * north-south at 0, 0, 0 with positive Z pointing south (but since the earth + * is round it isn't exactly north-south as you move east or west of 0, 0, 0). + * One unit is one meter and the point 0,0,0 is on the surface of the earth at + * sea level for some latitude and longitude picked by the sim such that the + * user's aircraft is reasonably nearby. + * + * 2-d Panel coordinates are 2d, with the X axis horizontal and the Y axis + * vertical. The point 0,0 is the bottom left and 1024,768 is the upper + * right of the screen. This is true no matter what resolution the user's + * monitor is in; when running in higher resolution, graphics will be + * scaled. + * + * Use X-Plane's routines to convert between global and local coordinates. Do + * not attempt to do this conversion yourself; the precise 'roundness' of + * X-Plane's physics model may not match your own, and (to make things + * weirder) the user can potentially customize the physics of the current + * planet. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * X-PLANE GRAPHICS + ***************************************************************************/ +/* + * These routines allow you to use OpenGL with X-Plane. + * + */ + + +/* + * XPLMTextureID + * + * XPLM Texture IDs name well-known textures in the sim for you to use. This + * allows you to recycle textures from X-Plane, saving VRAM. + * + * *Warning*: do not use these enums. The only remaining use they have is to + * access the legacy compatibility v10 UI texture; if you need this, get it + * via the Widgets library. + * + */ +enum { + /* The bitmap that contains window outlines, button outlines, fonts, etc. */ + xplm_Tex_GeneralInterface = 0, + +#if defined(XPLM_DEPRECATED) + /* The exterior paint for the user's aircraft (daytime). */ + xplm_Tex_AircraftPaint = 1, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* The exterior light map for the user's aircraft. */ + xplm_Tex_AircraftLiteMap = 2, + +#endif /* XPLM_DEPRECATED */ + +}; +typedef int XPLMTextureID; + +/* + * XPLMSetGraphicsState + * + * XPLMSetGraphicsState changes OpenGL's fixed function pipeline state. You + * are not responsible for restoring any state that is accessed via + * XPLMSetGraphicsState, but you are responsible for not accessing this state + * directly. + * + * - inEnableFog - enables or disables fog, equivalent to: glEnable(GL_FOG); + * - inNumberTexUnits - enables or disables a number of multitexturing units. + * If the number is 0, 2d texturing is disabled entirely, as in + * glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a + * number of multitexturing units are enabled sequentially, starting with + * unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB); glEnable + * (GL_TEXTURE_2D); + * - inEnableLighting - enables or disables OpenGL lighting, e.g. + * glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + * - inEnableAlphaTesting - enables or disables the alpha test per pixel, e.g. + * glEnable(GL_ALPHA_TEST); + * - inEnableAlphaBlending - enables or disables alpha blending per pixel, + * e.g. glEnable(GL_BLEND); + * - inEnableDepthTesting - enables per pixel depth testing, as in + * glEnable(GL_DEPTH_TEST); + * - inEnableDepthWriting - enables writing back of depth information to the + * depth bufffer, as in glDepthMask(GL_TRUE); + * + * The purpose of this function is to change OpenGL state while keeping + * X-Plane aware of the state changes; this keeps X-Plane from getting + * surprised by OGL state changes, and prevents X-Plane and plug-ins from + * having to set all state before all draws; XPLMSetGraphicsState internally + * skips calls to change state that is already properly enabled. + * + * X-Plane does not have a 'default' OGL state for plug-ins with respect to + * the above state vector; plug-ins should totally set OGL state using this + * API before drawing. Use XPLMSetGraphicsState instead of any of the above + * OpenGL calls. + * + * WARNING: Any routine that performs drawing (e.g. XPLMDrawString or widget + * code) may change X-Plane's state. Always set state before drawing after + * unknown code has executed. + * + * *Deprecation Warnings*: X-Plane's lighting and fog environemnt is + * significantly more complex than the fixed function pipeline can express; + * do not assume that lighting and fog state is a good approximation for 3-d + * drawing. Prefer to use XPLMInstancing to draw objects. All calls to + * XPLMSetGraphicsState should have no fog or lighting. + * + */ +XPLM_API void XPLMSetGraphicsState( + int inEnableFog, + int inNumberTexUnits, + int inEnableLighting, + int inEnableAlphaTesting, + int inEnableAlphaBlending, + int inEnableDepthTesting, + int inEnableDepthWriting); + +/* + * XPLMBindTexture2d + * + * XPLMBindTexture2d changes what texture is bound to the 2d texturing + * target. This routine caches the current 2d texture across all texturing + * units in the sim and plug-ins, preventing extraneous binding. For + * example, consider several plug-ins running in series; if they all use the + * 'general interface' bitmap to do UI, calling this function will skip the + * rebinding of the general interface texture on all but the first plug-in, + * which can provide better frame rate son some graphics cards. + * + * inTextureID is the ID of the texture object to bind; inTextureUnit is a + * zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 + * units. (This number may increase in future versions of X-Plane.) + * + * Use this routine instead of glBindTexture(GL_TEXTURE_2D, ....); + * + */ +XPLM_API void XPLMBindTexture2d( + int inTextureNum, + int inTextureUnit); + +/* + * XPLMGenerateTextureNumbers + * + * Use this routine instead of glGenTextures to generate new texture object + * IDs. This routine historically ensured that plugins don't use texure IDs + * that X-Plane is reserving for its own use. + * + */ +XPLM_API void XPLMGenerateTextureNumbers( + int * outTextureIDs, + int inCount); + +#if defined(XPLM_DEPRECATED) +/* + * XPLMGetTexture + * + * XPLMGetTexture returns the OpenGL texture ID of an X-Plane texture based on + * a generic identifying code. For example, you can get the texture for + * X-Plane's UI bitmaps. + * + */ +XPLM_API int XPLMGetTexture( + XPLMTextureID inTexture); +#endif /* XPLM_DEPRECATED */ + +/* + * XPLMWorldToLocal + * + * This routine translates coordinates from latitude, longitude, and altitude + * to local scene coordinates. Latitude and longitude are in decimal degrees, + * and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + * meters in the local OpenGL coordinate system. + * + */ +XPLM_API void XPLMWorldToLocal( + double inLatitude, + double inLongitude, + double inAltitude, + double * outX, + double * outY, + double * outZ); + +/* + * XPLMLocalToWorld + * + * This routine translates a local coordinate triplet back into latitude, + * longitude, and altitude. Latitude and longitude are in decimal degrees, + * and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + * meters in the local OpenGL coordinate system. + * + * NOTE: world coordinates are less precise than local coordinates; you should + * try to avoid round tripping from local to world and back. + * + */ +XPLM_API void XPLMLocalToWorld( + double inX, + double inY, + double inZ, + double * outLatitude, + double * outLongitude, + double * outAltitude); + +/* + * XPLMDrawTranslucentDarkBox + * + * This routine draws a translucent dark box, partially obscuring parts of the + * screen but making text easy to read. This is the same graphics primitive + * used by X-Plane to show text files and ATC info. + * + */ +XPLM_API void XPLMDrawTranslucentDarkBox( + int inLeft, + int inTop, + int inRight, + int inBottom); + +/*************************************************************************** + * X-PLANE TEXT + ***************************************************************************/ + +/* + * XPLMFontID + * + * X-Plane features some fixed-character fonts. Each font may have its own + * metrics. + * + * WARNING: Some of these fonts are no longer supported or may have changed + * geometries. For maximum copmatibility, see the comments below. + * + * Note: X-Plane 7 supports proportional-spaced fonts. Since no measuring + * routine is available yet, the SDK will normally draw using a fixed-width + * font. You can use a dataref to enable proportional font drawing on XP7 if + * you want to. + * + */ +enum { + /* Mono-spaced font for user interface. Available in all versions of the SDK.*/ + xplmFont_Basic = 0, + +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Menus = 1, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Metal = 2, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Led = 3, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_LedWide = 4, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelHUD = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelEFIS = 6, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelGPS = 7, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosGA = 8, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosBC = 9, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosHM = 10, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosGANarrow = 11, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosBCNarrow = 12, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosHMNarrow = 13, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Timer = 14, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_FullRound = 15, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_SmallRound = 16, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Menus_Localized = 17, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM200) + /* Proportional UI font. */ + xplmFont_Proportional = 18, + +#endif /* XPLM200 */ + +}; +typedef int XPLMFontID; + +/* + * XPLMDrawString + * + * This routine draws a NULL termianted string in a given font. Pass in the + * lower left pixel that the character is to be drawn onto. Also pass the + * character and font ID. This function returns the x offset plus the width of + * all drawn characters. The color to draw in is specified as a pointer to an + * array of three floating point colors, representing RGB intensities from 0.0 + * to 1.0. + * + */ +XPLM_API void XPLMDrawString( + float * inColorRGB, + int inXOffset, + int inYOffset, + char * inChar, + int * inWordWrapWidth, /* Can be NULL */ + XPLMFontID inFontID); + +/* + * XPLMDrawNumber + * + * This routine draws a number similar to the digit editing fields in + * PlaneMaker and data output display in X-Plane. Pass in a color, a + * position, a floating point value, and formatting info. Specify how many + * integer and how many decimal digits to show and whether to show a sign, as + * well as a character set. This routine returns the xOffset plus width of the + * string drawn. + * + */ +XPLM_API void XPLMDrawNumber( + float * inColorRGB, + int inXOffset, + int inYOffset, + double inValue, + int inDigits, + int inDecimals, + int inShowSign, + XPLMFontID inFontID); + +/* + * XPLMGetFontDimensions + * + * This routine returns the width and height of a character in a given font. + * It also tells you if the font only supports numeric digits. Pass NULL if + * you don't need a given field. Note that for a proportional font the width + * will be an arbitrary, hopefully average width. + * + */ +XPLM_API void XPLMGetFontDimensions( + XPLMFontID inFontID, + int * outCharWidth, /* Can be NULL */ + int * outCharHeight, /* Can be NULL */ + int * outDigitsOnly); /* Can be NULL */ + +#if defined(XPLM200) +/* + * XPLMMeasureString + * + * This routine returns the width in pixels of a string using a given font. + * The string is passed as a pointer plus length (and does not need to be null + * terminated); this is used to allow for measuring substrings. The return + * value is floating point; it is possible that future font drawing may allow + * for fractional pixels. + * + */ +XPLM_API float XPLMMeasureString( + XPLMFontID inFontID, + const char * inChar, + int inNumChars); +#endif /* XPLM200 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMInstance.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMInstance.h new file mode 100644 index 0000000..d2a8f2c --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMInstance.h @@ -0,0 +1,136 @@ +#ifndef _XPLMInstance_h_ +#define _XPLMInstance_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMInstance + ***************************************************************************/ +/* + * This API provides instanced drawing of X-Plane objects (.obj files). In + * contrast to old drawing APIs, which required you to draw your own objects + * per-frame, the instancing API allows you to simply register an OBJ for + * drawing, then move or manipulate it later (as needed). + * + * This provides one tremendous benefit: it keeps all dataref operations for + * your object in one place. Because datarefs are main thread only, allowing + * dataref access anywhere is a serious performance bottleneck for the + * simulator---the whole simulator has to pause and wait for each dataref + * access. This performance penalty will only grow worse as X-Plane moves + * toward an ever more heavily multithreaded engine. + * + * The instancing API allows X-Plane to isolate all dataref manipulations for + * all plugin object drawing to one place, potentially providing huge + * performance gains. + * + * Here's how it works: + * + * When an instance is created, it provides a list of all datarefs you want to + * manipulate in for the OBJ in the future. This list of datarefs replaces the + * ad-hoc collections of dataref objects previously used by art assets. Then, + * per-frame, you can manipulate the instance by passing in a "block" of + * packed floats representing the current values of the datarefs for your + * instance. (Note that the ordering of this set of packed floats must exactly + * match the ordering of the datarefs when you created your instance.) + * + */ + +#include "XPLMDefs.h" +#include "XPLMScenery.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * Instance Creation and Destruction + ***************************************************************************/ +/* + * Registers and unregisters instances. + * + */ + + +/* + * XPLMInstanceRef + * + * An opaque handle to an instance. + * + */ +typedef void * XPLMInstanceRef; + +/* + * XPLMCreateInstance + * + * XPLMCreateInstance creates a new instance, managed by your plug-in, and + * returns a handle to the instance. A few important requirements: + * + * * The object passed in must be fully loaded and returned from the XPLM + * before you can create your instance; you cannot pass a null obj ref, nor + * can you change the ref later. + * + * * If you use any custom datarefs in your object, they must be registered + * before the object is loaded. This is true even if their data will be + * provided via the instance dataref list. + * + * * The instance dataref array must be a valid ptr to an array of at least + * one item that is null terminated. That is, if you do not want any + * datarefs, you must passa ptr to an array with a null item. You cannot + * pass null for this. + * + */ +XPLM_API XPLMInstanceRef XPLMCreateInstance( + XPLMObjectRef obj, + const char ** datarefs); + +/* + * XPLMDestroyInstance + * + * XPLMDestroyInstance destroys and deallocates your instance; once called, + * you are still responsible for releasing the OBJ ref. + * + * Tip: you can release your OBJ ref after you call XPLMCreateInstance as long + * as you never use it again; the instance will maintain its own reference to + * the OBJ and the object OBJ be deallocated when the instance is destroyed. + * + */ +XPLM_API void XPLMDestroyInstance( + XPLMInstanceRef instance); + +/*************************************************************************** + * Instance Manipulation + ***************************************************************************/ + +/* + * XPLMInstanceSetPosition + * + * Updates both the position of the instance and all datarefs you registered + * for it. Call this from a flight loop callback or UI callback. + * + * __DO NOT__ call XPLMInstanceSetPosition from a drawing callback; the whole + * point of instancing is that you do not need any drawing callbacks. Setting + * instance data from a drawing callback may have undefined consequences, and + * the drawing callback hurts FPS unnecessarily. + * + * The memory pointed to by the data pointer must be large enough to hold one + * float for every data ref you have registered, and must contain valid + * floating point data. + * + * BUG: before X-Plane 11.50, if you have no dataref registered, you must + * still pass a valid pointer for data and not null. + * + */ +XPLM_API void XPLMInstanceSetPosition( + XPLMInstanceRef instance, + const XPLMDrawInfo_t * new_position, + const float * data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMMap.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMMap.h new file mode 100644 index 0000000..18c055a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMMap.h @@ -0,0 +1,631 @@ +#ifndef _XPLMMap_h_ +#define _XPLMMap_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMMap + ***************************************************************************/ +/* + * This API allows you to create new layers within X-Plane maps. Your layers + * can draw arbitrary OpenGL, but they conveniently also have access to + * X-Plane's built-in icon and label drawing functions. + * + * As of X-Plane 11, map drawing happens in three stages: + * + * 1. backgrounds and "fill," + * 2. icons, and + * 3. labels. + * + * Thus, all background drawing gets layered beneath all icons, which likewise + * get layered beneath all labels. Within each stage, the map obeys a + * consistent layer ordering, such that "fill" layers (layers that cover a + * large amount of map area, like the terrain and clouds) appear beneath + * "markings" layers (like airport icons). This ensures that layers with fine + * details don't get obscured by layers with larger details. + * + * The XPLM map API reflects both aspects of this draw layering: you can + * register a layer as providing either markings or fill, and X-Plane will + * draw your fill layers beneath your markings layers (regardless of + * registration order). Likewise, you are guaranteed that your layer's icons + * (added from within an icon callback) will go above your layer's OpenGL + * drawing, and your labels will go above your icons. + * + * The XPLM guarantees that all plugin-created fill layers go on top of all + * native X-Plane fill layers, and all plugin-created markings layers go on + * top of all X-Plane markings layers (with the exception of the aircraft + * icons). It also guarantees that the draw order of your own plugin's layers + * will be consistent. But, for layers created by different plugins, the only + * guarantee is that we will draw all of one plugin's layers of each type + * (fill, then markings), then all of the others'; we don't guarantee which + * plugin's fill and markings layers go on top of the other's. + * + * As of X-Plane 11, maps use true cartographic projections for their drawing, + * and different maps may use different projections. For that reason, all + * drawing calls include an opaque handle for the projection you should use to + * do the drawing. Any time you would draw at a particular latitude/longitude, + * you'll need to ask the projection to translate that position into "map + * coordinates." (Note that the projection is guaranteed not to change between + * calls to your prepare-cache hook, so if you cache your map coordinates + * ahead of time, there's no need to re-project them when you actually draw.) + * + * In addition to mapping normal latitude/longitude locations into map + * coordinates, the projection APIs also let you know the current heading for + * north. (Since X-Plane 11 maps can rotate to match the heading of the user's + * aircraft, it's not safe to assume that north is at zero degrees rotation.) + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XPLM300) +/*************************************************************************** + * DRAWING CALLBACKS + ***************************************************************************/ +/* + * When you create a new map layer (using XPLMCreateMapLayer), you can provide + * any or all of these callbacks. They allow you to insert your own OpenGL + * drawing, text labels, and icons into the X-Plane map at the appropriate + * places, allowing your layer to behave as similarly to X-Plane's built-in + * layers as possible. + * + */ + + +/* + * XPLMMapLayerID + * + * This is an opaque handle for a plugin-created map layer. Pass it to the map + * drawing APIs from an appropriate callback to draw in the layer you created. + * + */ +typedef void * XPLMMapLayerID; + +/* + * XPLMMapProjectionID + * + * This is an opaque handle for a map projection. Pass it to the projection + * APIs to translate between map coordinates and latitude/longitudes. + * + */ +typedef void * XPLMMapProjectionID; + +/* + * XPLMMapStyle + * + * Indicates the visual style being drawn by the map. In X-Plane, the user can + * choose between a number of map types, and different map types may have use + * a different visual representation for the same elements (for instance, the + * visual style of the terrain layer changes drastically between the VFR and + * IFR layers), or certain layers may be disabled entirely in some map types + * (e.g., localizers are only visible in the IFR low-enroute style). + * + */ +enum { + xplm_MapStyle_VFR_Sectional = 0, + + xplm_MapStyle_IFR_LowEnroute = 1, + + xplm_MapStyle_IFR_HighEnroute = 2, + + +}; +typedef int XPLMMapStyle; + +/* + * XPLMMapDrawingCallback_f + * + * This is the OpenGL map drawing callback for plugin-created map layers. You + * can perform arbitrary OpenGL drawing from this callback, with one + * exception: changes to the Z-buffer are not permitted, and will result in + * map drawing errors. + * + * All drawing done from within this callback appears beneath all built-in + * X-Plane icons and labels, but above the built-in "fill" layers (layers + * providing major details, like terrain and water). Note, however, that the + * relative ordering between the drawing callbacks of different plugins is not + * guaranteed. + * + */ +typedef void (* XPLMMapDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapIconDrawingCallback_f + * + * This is the icon drawing callback that enables plugin-created map layers to + * draw icons using X-Plane's built-in icon drawing functionality. You can + * request an arbitrary number of PNG icons to be drawn via + * XPLMDrawMapIconFromSheet() from within this callback, but you may not + * perform any OpenGL drawing here. + * + * Icons enqueued by this function will appear above all OpenGL drawing + * (performed by your optional XPLMMapDrawingCallback_f), and above all + * built-in X-Plane map icons of the same layer type ("fill" or "markings," as + * determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + * however, that the relative ordering between the drawing callbacks of + * different plugins is not guaranteed. + * + */ +typedef void (* XPLMMapIconDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapLabelDrawingCallback_f + * + * This is the label drawing callback that enables plugin-created map layers + * to draw text labels using X-Plane's built-in labeling functionality. You + * can request an arbitrary number of text labels to be drawn via + * XPLMDrawMapLabel() from within this callback, but you may not perform any + * OpenGL drawing here. + * + * Labels enqueued by this function will appear above all OpenGL drawing + * (performed by your optional XPLMMapDrawingCallback_f), and above all + * built-in map icons and labels of the same layer type ("fill" or "markings," + * as determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + * however, that the relative ordering between the drawing callbacks of + * different plugins is not guaranteed. + * + */ +typedef void (* XPLMMapLabelDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * LAYER MANAGEMENT CALLBACKS + ***************************************************************************/ +/* + * These are various "bookkeeping" callbacks that your map layer can receive + * (if you provide the callback in your XPLMCreateMapLayer_t). They allow you + * to manage the lifecycle of your layer, as well as cache any + * computationally-intensive preparation you might need for drawing. + * + */ + + +/* + * XPLMMapPrepareCacheCallback_f + * + * A callback used to allow you to cache whatever information your layer needs + * to draw in the current map area. + * + * This is called each time the map's total bounds change. This is typically + * triggered by new DSFs being loaded, such that X-Plane discards old, + * now-distant DSFs and pulls in new ones. At that point, the available bounds + * of the map also change to match the new DSF area. + * + * By caching just the information you need to draw in this area, your future + * draw calls can be made faster, since you'll be able to simply "splat" your + * precomputed information each frame. + * + * We guarantee that the map projection will not change between successive + * prepare cache calls, nor will any draw call give you bounds outside these + * total map bounds. So, if you cache the projected map coordinates of all the + * items you might want to draw in the total map area, you can be guaranteed + * that no draw call will be asked to do any new work. + * + */ +typedef void (* XPLMMapPrepareCacheCallback_f)( + XPLMMapLayerID inLayer, + const float * inTotalMapBoundsLeftTopRightBottom, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapWillBeDeletedCallback_f + * + * Called just before your map layer gets deleted. Because SDK-created map + * layers have the same lifetime as the X-Plane map that contains them, if the + * map gets unloaded from memory, your layer will too. + * + */ +typedef void (* XPLMMapWillBeDeletedCallback_f)( + XPLMMapLayerID inLayer, + void * inRefcon); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP LAYER CREATION AND DESTRUCTION + ***************************************************************************/ +/* + * Enables the creation of new map layers. Layers are created for a particular + * instance of the X-Plane map. For instance, if you want your layer to appear + * in both the normal map interface and the Instructor Operator Station (IOS), + * you would need two separate calls to XPLMCreateMapLayer(), with two + * different values for your XPLMCreateMapLayer_t::layer_name. + * + * Your layer's lifetime will be determined by the lifetime of the map it is + * created in. If the map is destroyed (on the X-Plane side), your layer will + * be too, and you'll receive a callback to your + * XPLMMapWillBeDeletedCallback_f. + * + */ + + +/* + * XPLMMapLayerType + * + * Indicates the type of map layer you are creating. Fill layers will always + * be drawn beneath markings layers. + * + */ +enum { + /* A layer that draws "fill" graphics, like weather patterns, terrain, etc. * + * Fill layers frequently cover a large portion of the visible map area. */ + xplm_MapLayer_Fill = 0, + + /* A layer that provides markings for particular map features, like NAVAIDs, * + * airports, etc. Even dense markings layers cover a small portion of the * + * total map area. */ + xplm_MapLayer_Markings = 1, + + +}; +typedef int XPLMMapLayerType; + +/* Globally unique identifier for X-Plane's Map window, used as the * + * mapToCreateLayerIn parameter in XPLMCreateMapLayer_t */ +#define XPLM_MAP_USER_INTERFACE "XPLM_MAP_USER_INTERFACE" + +/* Globally unique identifier for X-Plane's Instructor Operator Station * + * window, used as the mapToCreateLayerIn parameter in XPLMCreateMapLayer_t */ +#define XPLM_MAP_IOS "XPLM_MAP_IOS" + +/* + * XPLMCreateMapLayer_t + * + * This structure defines all of the parameters used to create a map layer + * using XPLMCreateMapLayer. The structure will be expanded in future SDK APIs + * to include more features. Always set the structSize member to the size of + * your struct in bytes! + * + * Each layer must be associated with exactly one map instance in X-Plane. + * That map, and that map alone, will call your callbacks. Likewise, when that + * map is deleted, your layer will be as well. + * + */ +typedef struct { + /* Used to inform XPLMCreateMapLayer() of the SDK version you compiled * + * against; should always be set to sizeof(XPLMCreateMapLayer_t) */ + int structSize; + /* Globally unique string identifying the map you want this layer to appear * + * in. As of XPLM300, this is limited to one of XPLM_MAP_USER_INTERFACE or * + * XPLM_MAP_IOS */ + const char * mapToCreateLayerIn; + /* The type of layer you are creating, used to determine draw order (all * + * plugin-created markings layers are drawn above all plugin-created fill * + * layers) */ + XPLMMapLayerType layerType; + /* Optional callback to inform you this layer is being deleted (due to its * + * owning map being destroyed) */ + XPLMMapWillBeDeletedCallback_f willBeDeletedCallback; + /* Optional callback you want to use to prepare your draw cache when the map * + * bounds change (set to NULL if you don't want this callback) */ + XPLMMapPrepareCacheCallback_f prepCacheCallback; + /* Optional callback you want to use for arbitrary OpenGL drawing, which goes * + * beneath all icons in the map's layering system (set to NULL if you don't * + * want this callback) */ + XPLMMapDrawingCallback_f drawCallback; + /* Optional callback you want to use for drawing icons, which go above all * + * built-in X-Plane icons (except the aircraft) in the map's layering system * + * (set to NULL if you don't want this callback) */ + XPLMMapIconDrawingCallback_f iconCallback; + /* Optional callback you want to use for drawing map labels, which go above * + * all built-in X-Plane icons and labels (except those of aircraft) in the * + * map's layering system (set to NULL if you don't want this callback) */ + XPLMMapLabelDrawingCallback_f labelCallback; + /* True if you want a checkbox to be created in the map UI to toggle this * + * layer on and off; false if the layer should simply always be enabled */ + int showUiToggle; + /* Short label to use for this layer in the user interface */ + const char * layerName; + /* A reference to arbitrary data that will be passed to your callbacks */ + void * refcon; +} XPLMCreateMapLayer_t; + +/* + * XPLMCreateMapLayer + * + * This routine creates a new map layer. You pass in an XPLMCreateMapLayer_t + * structure with all of the fields set in. You must set the structSize of + * the structure to the size of the actual structure you used. + * + * Returns NULL if the layer creation failed. This happens most frequently + * because the map you specified in your + * XPLMCreateMapLayer_t::mapToCreateLayerIn field doesn't exist (that is, if + * XPLMMapExists() returns 0 for the specified map). You can use + * XPLMRegisterMapCreationHook() to get a notification each time a new map is + * opened in X-Plane, at which time you can create layers in it. + * + */ +XPLM_API XPLMMapLayerID XPLMCreateMapLayer( + XPLMCreateMapLayer_t * inParams); + +/* + * XPLMDestroyMapLayer + * + * Destroys a map layer you created (calling your + * XPLMMapWillBeDeletedCallback_f if applicable). Returns true if a deletion + * took place. + * + */ +XPLM_API int XPLMDestroyMapLayer( + XPLMMapLayerID inLayer); + +/* + * XPLMMapCreatedCallback_f + * + * A callback to notify your plugin that a new map has been created in + * X-Plane. This is the best time to add a custom map layer using + * XPLMCreateMapLayer(). + * + * No OpenGL drawing is permitted within this callback. + * + */ +typedef void (* XPLMMapCreatedCallback_f)( + const char * mapIdentifier, + void * refcon); + +/* + * XPLMRegisterMapCreationHook + * + * Registers your callback to receive a notification each time a new map is + * constructed in X-Plane. This callback is the best time to add your custom + * map layer using XPLMCreateMapLayer(). + * + * Note that you will not be notified about any maps that already exist---you + * can use XPLMMapExists() to check for maps that were created previously. + * + */ +XPLM_API void XPLMRegisterMapCreationHook( + XPLMMapCreatedCallback_f callback, + void * refcon); + +/* + * XPLMMapExists + * + * Returns 1 if the map with the specified identifier already exists in + * X-Plane. In that case, you can safely call XPLMCreateMapLayer() specifying + * that your layer should be added to that map. + * + */ +XPLM_API int XPLMMapExists( + const char * mapIdentifier); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP DRAWING + ***************************************************************************/ +/* + * These APIs are only valid from within a map drawing callback (one of + * XPLMIconDrawingCallback_t or XPLMMapLabelDrawingCallback_f). Your drawing + * callbacks are registered when you create a new map layer as part of your + * XPLMCreateMapLayer_t. The functions here hook into X-Plane's built-in map + * drawing functionality for icons and labels, so that you get a consistent + * style with the rest of the X-Plane map. + * + * Note that the X-Plane 11 map introduces a strict ordering: layers of type + * xplm_MapLayer_Fill get drawn beneath all xplm_MapLayer_Markings layers. + * Likewise, all OpenGL drawing (performed in your layer's + * XPLMMapDrawingCallback_f) will appear beneath any icons and labels you + * draw. + * + */ + + +/* + * XPLMMapOrientation + * + * Indicates whether a map element should be match its rotation to the map + * itself, or to the user interface. For instance, the map itself may be + * rotated such that "up" matches the user's aircraft, but you may want to + * draw a text label such that it is always rotated zero degrees relative to + * the user's perspective. In that case, you would have it draw with UI + * orientation. + * + */ +enum { + /* Orient such that a 0 degree rotation matches the map's north */ + xplm_MapOrientation_Map = 0, + + /* Orient such that a 0 degree rotation is "up" relative to the user interface*/ + xplm_MapOrientation_UI = 1, + + +}; +typedef int XPLMMapOrientation; + +/* + * XPLMDrawMapIconFromSheet + * + * Enables plugin-created map layers to draw PNG icons using X-Plane's + * built-in icon drawing functionality. Only valid from within an + * XPLMIconDrawingCallback_t (but you can request an arbitrary number of icons + * to be drawn from within your callback). + * + * X-Plane will automatically manage the memory for your texture so that it + * only has to be loaded from disk once as long as you continue drawing it + * per-frame. (When you stop drawing it, the memory may purged in a "garbage + * collection" pass, require a load from disk in the future.) + * + * Instead of having X-Plane draw a full PNG, this method allows you to use UV + * coordinates to request a portion of the image to be drawn. This allows you + * to use a single texture load (of an icon sheet, for example) to draw many + * icons. Doing so is much more efficient than drawing a dozen different small + * PNGs. + * + * The UV coordinates used here treat the texture you load as being comprised + * of a number of identically sized "cells." You specify the width and height + * in cells (ds and dt, respectively), as well as the coordinates within the + * cell grid for the sub-image you'd like to draw. + * + * Note that you can use different ds and dt values in subsequent calls with + * the same texture sheet. This enables you to use icons of different sizes in + * the same sheet if you arrange them properly in the PNG. + * + * This function is only valid from within an XPLMIconDrawingCallback_t (but + * you can request an arbitrary number of icons to be drawn from within your + * callback). + * + */ +XPLM_API void XPLMDrawMapIconFromSheet( + XPLMMapLayerID layer, + const char * inPngPath, + int s, + int t, + int ds, + int dt, + float mapX, + float mapY, + XPLMMapOrientation orientation, + float rotationDegrees, + float mapWidth); + +/* + * XPLMDrawMapLabel + * + * Enables plugin-created map layers to draw text labels using X-Plane's + * built-in labeling functionality. Only valid from within an + * XPLMMapLabelDrawingCallback_f (but you can request an arbitrary number of + * text labels to be drawn from within your callback). + * + */ +XPLM_API void XPLMDrawMapLabel( + XPLMMapLayerID layer, + const char * inText, + float mapX, + float mapY, + XPLMMapOrientation orientation, + float rotationDegrees); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP PROJECTIONS + ***************************************************************************/ +/* + * As of X-Plane 11, the map draws using true cartographic projections, and + * different maps may use different projections. Thus, to draw at a particular + * latitude and longitude, you must first transform your real-world + * coordinates into map coordinates. + * + * The map projection is also responsible for giving you the current scale of + * the map. That is, the projection can tell you how many map units correspond + * to 1 meter at a given point. + * + * Finally, the map projection can give you the current rotation of the map. + * Since X-Plane 11 maps can rotate to match the heading of the aircraft, the + * map's rotation can potentially change every frame. + * + */ + + +/* + * XPLMMapProject + * + * Projects a latitude/longitude into map coordinates. This is the inverse of + * XPLMMapUnproject(). + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API void XPLMMapProject( + XPLMMapProjectionID projection, + double latitude, + double longitude, + float * outX, + float * outY); + +/* + * XPLMMapUnproject + * + * Transforms map coordinates back into a latitude and longitude. This is the + * inverse of XPLMMapProject(). + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API void XPLMMapUnproject( + XPLMMapProjectionID projection, + float mapX, + float mapY, + double * outLatitude, + double * outLongitude); + +/* + * XPLMMapScaleMeter + * + * Returns the number of map units that correspond to a distance of one meter + * at a given set of map coordinates. + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API float XPLMMapScaleMeter( + XPLMMapProjectionID projection, + float mapX, + float mapY); + +/* + * XPLMMapGetNorthHeading + * + * Returns the heading (in degrees clockwise from "up") that corresponds to + * north at a given point on the map. In other words, if your runway has a + * true heading of 360, you would use "north" as the Cartesian angle at which + * to draw the runway on the map. (You would add the result of + * XPLMMapGetNorthHeading() to your true heading to get the map angle.) + * + * This is necessary becuase X-Plane's map can be rotated to match your + * aircraft's orientation; north is not always "up." + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API float XPLMMapGetNorthHeading( + XPLMMapProjectionID projection, + float mapX, + float mapY); + +#endif /* XPLM300 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMMenus.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMMenus.h new file mode 100644 index 0000000..f5802ab --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMMenus.h @@ -0,0 +1,290 @@ +#ifndef _XPLMMenus_h_ +#define _XPLMMenus_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMMenus + ***************************************************************************/ +/* + * Plug-ins can create menus in the menu bar of X-Plane. This is done by + * creating a menu and then creating items. Menus are referred to by an + * opaque ID. Items are referred to by (zero-based) index number. + * + * Menus are "sandboxed" between plugins---no plugin can access the menus of + * any other plugin. Furthermore, all menu indices are relative to your + * plugin's menus only; if your plugin creates two sub-menus in the Plugins + * menu at different times, it doesn't matter how many other plugins also + * create sub-menus of Plugins in the intervening time: your sub-menus will be + * given menu indices 0 and 1. (The SDK does some work in the back-end to + * filter out menus that are irrelevant to your plugin in order to deliver + * this consistency for each plugin.) + * + * When you create a menu item, you specify how we should handle clicks on + * that menu item. You can either have the XPLM trigger a callback (the + * XPLMMenuHandler_f associated with the menu that contains the item), or you + * can simply have a command be triggered (with no associated call to your + * menu handler). The advantage of the latter method is that X-Plane will + * display any keyboard shortcuts associated with the command. (In contrast, + * there are no keyboard shortcuts associated with menu handler callbacks with + * specific parameters.) + * + * Menu text in X-Plane is UTF8; X-Plane's character set covers latin, greek + * and cyrillic characters, Katakana, as well as some Japanese symbols. Some + * APIs have a inDeprecatedAndIgnored parameter that used to select a + * character set; since X-Plane 9 all localization is done via UTF-8 only. + * + */ + +#include "XPLMDefs.h" +#include "XPLMUtilities.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * XPLM MENUS + ***************************************************************************/ + +/* + * XPLMMenuCheck + * + * These enumerations define the various 'check' states for an X-Plane menu. + * 'checking' in X-Plane actually appears as a light which may or may not be + * lit. So there are three possible states. + * + */ +enum { + /* there is no symbol to the left of the menu item. */ + xplm_Menu_NoCheck = 0, + + /* the menu has a mark next to it that is unmarked (not lit). */ + xplm_Menu_Unchecked = 1, + + /* the menu has a mark next to it that is checked (lit). */ + xplm_Menu_Checked = 2, + + +}; +typedef int XPLMMenuCheck; + +/* + * XPLMMenuID + * + * This is a unique ID for each menu you create. + * + */ +typedef void * XPLMMenuID; + +/* + * XPLMMenuHandler_f + * + * A menu handler function takes two reference pointers, one for the menu + * (specified when the menu was created) and one for the item (specified when + * the item was created). + * + */ +typedef void (* XPLMMenuHandler_f)( + void * inMenuRef, + void * inItemRef); + +/* + * XPLMFindPluginsMenu + * + * This function returns the ID of the plug-ins menu, which is created for you + * at startup. + * + */ +XPLM_API XPLMMenuID XPLMFindPluginsMenu(void); + +#if defined(XPLM300) +/* + * XPLMFindAircraftMenu + * + * This function returns the ID of the menu for the currently-loaded aircraft, + * used for showing aircraft-specific commands. + * + * The aircraft menu is created by X-Plane at startup, but it remains hidden + * until it is populated via XPLMAppendMenuItem() or + * XPLMAppendMenuItemWithCommand(). + * + * Only plugins loaded with the user's current aircraft are allowed to access + * the aircraft menu. For all other plugins, this will return NULL, and any + * attempts to add menu items to it will fail. + * + */ +XPLM_API XPLMMenuID XPLMFindAircraftMenu(void); +#endif /* XPLM300 */ + +/* + * XPLMCreateMenu + * + * This function creates a new menu and returns its ID. It returns NULL if + * the menu cannot be created. Pass in a parent menu ID and an item index to + * create a submenu, or NULL for the parent menu to put the menu in the menu + * bar. The menu's name is only used if the menu is in the menubar. You also + * pass a handler function and a menu reference value. Pass NULL for the + * handler if you do not need callbacks from the menu (for example, if it only + * contains submenus). + * + * Important: you must pass a valid, non-empty menu title even if the menu is + * a submenu where the title is not visible. + * + */ +XPLM_API XPLMMenuID XPLMCreateMenu( + const char * inName, + XPLMMenuID inParentMenu, + int inParentItem, + XPLMMenuHandler_f inHandler, + void * inMenuRef); + +/* + * XPLMDestroyMenu + * + * This function destroys a menu that you have created. Use this to remove a + * submenu if necessary. (Normally this function will not be necessary.) + * + */ +XPLM_API void XPLMDestroyMenu( + XPLMMenuID inMenuID); + +/* + * XPLMClearAllMenuItems + * + * This function removes all menu items from a menu, allowing you to rebuild + * it. Use this function if you need to change the number of items on a menu. + * + */ +XPLM_API void XPLMClearAllMenuItems( + XPLMMenuID inMenuID); + +/* + * XPLMAppendMenuItem + * + * This routine appends a new menu item to the bottom of a menu and returns + * its index. Pass in the menu to add the item to, the items name, and a void + * * ref for this item. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + * Note that all menu indices returned are relative to your plugin's menus + * only; if your plugin creates two sub-menus in the Plugins menu at different + * times, it doesn't matter how many other plugins also create sub-menus of + * Plugins in the intervening time: your sub-menus will be given menu indices + * 0 and 1. (The SDK does some work in the back-end to filter out menus that + * are irrelevant to your plugin in order to deliver this consistency for each + * plugin.) + * + */ +XPLM_API int XPLMAppendMenuItem( + XPLMMenuID inMenu, + const char * inItemName, + void * inItemRef, + int inDeprecatedAndIgnored); + +#if defined(XPLM300) +/* + * XPLMAppendMenuItemWithCommand + * + * Like XPLMAppendMenuItem(), but instead of the new menu item triggering the + * XPLMMenuHandler_f of the containiner menu, it will simply execute the + * command you pass in. Using a command for your menu item allows the user to + * bind a keyboard shortcut to the command and see that shortcut represented + * in the menu. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + * Like XPLMAppendMenuItem(), all menu indices are relative to your plugin's + * menus only. + * + */ +XPLM_API int XPLMAppendMenuItemWithCommand( + XPLMMenuID inMenu, + const char * inItemName, + XPLMCommandRef inCommandToExecute); +#endif /* XPLM300 */ + +/* + * XPLMAppendMenuSeparator + * + * This routine adds a separator to the end of a menu. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + */ +XPLM_API void XPLMAppendMenuSeparator( + XPLMMenuID inMenu); + +/* + * XPLMSetMenuItemName + * + * This routine changes the name of an existing menu item. Pass in the menu + * ID and the index of the menu item. + * + */ +XPLM_API void XPLMSetMenuItemName( + XPLMMenuID inMenu, + int inIndex, + const char * inItemName, + int inDeprecatedAndIgnored); + +/* + * XPLMCheckMenuItem + * + * Set whether a menu item is checked. Pass in the menu ID and item index. + * + */ +XPLM_API void XPLMCheckMenuItem( + XPLMMenuID inMenu, + int index, + XPLMMenuCheck inCheck); + +/* + * XPLMCheckMenuItemState + * + * This routine returns whether a menu item is checked or not. A menu item's + * check mark may be on or off, or a menu may not have an icon at all. + * + */ +XPLM_API void XPLMCheckMenuItemState( + XPLMMenuID inMenu, + int index, + XPLMMenuCheck * outCheck); + +/* + * XPLMEnableMenuItem + * + * Sets whether this menu item is enabled. Items start out enabled. + * + */ +XPLM_API void XPLMEnableMenuItem( + XPLMMenuID inMenu, + int index, + int enabled); + +#if defined(XPLM210) +/* + * XPLMRemoveMenuItem + * + * Removes one item from a menu. Note that all menu items below are moved up + * one; your plugin must track the change in index numbers. + * + */ +XPLM_API void XPLMRemoveMenuItem( + XPLMMenuID inMenu, + int inIndex); +#endif /* XPLM210 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMNavigation.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMNavigation.h new file mode 100644 index 0000000..716caf0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMNavigation.h @@ -0,0 +1,362 @@ +#ifndef _XPLMNavigation_h_ +#define _XPLMNavigation_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMNavigation + ***************************************************************************/ +/* + * The XPLM Navigation APIs give you some access to the navigation databases + * inside X-Plane. X-Plane stores all navigation information in RAM, so by + * using these APIs you can gain access to most information without having to + * go to disk or parse the files yourself. + * + * You can also use this API to program the FMS. You must use the navigation + * APIs to find the nav-aids you want to program into the FMS, since the FMS + * is powered internally by X-Plane's navigation database. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * NAVIGATION DATABASE ACCESS + ***************************************************************************/ + +/* + * XPLMNavType + * + * These enumerations define the different types of navaids. They are each + * defined with a separate bit so that they may be bit-wise added together to + * form sets of nav-aid types. + * + * NOTE: xplm_Nav_LatLon is a specific lat-lon coordinate entered into the + * FMS. It will not exist in the database, and cannot be programmed into the + * FMS. Querying the FMS for navaids will return it. Use + * XPLMSetFMSEntryLatLon to set a lat/lon waypoint. + * + */ +enum { + xplm_Nav_Unknown = 0, + + xplm_Nav_Airport = 1, + + xplm_Nav_NDB = 2, + + xplm_Nav_VOR = 4, + + xplm_Nav_ILS = 8, + + xplm_Nav_Localizer = 16, + + xplm_Nav_GlideSlope = 32, + + xplm_Nav_OuterMarker = 64, + + xplm_Nav_MiddleMarker = 128, + + xplm_Nav_InnerMarker = 256, + + xplm_Nav_Fix = 512, + + xplm_Nav_DME = 1024, + + xplm_Nav_LatLon = 2048, + + +}; +typedef int XPLMNavType; + +/* + * XPLMNavRef + * + * XPLMNavRef is an iterator into the navigation database. The navigation + * database is essentially an array, but it is not necessarily densely + * populated. The only assumption you can safely make is that like-typed + * nav-aids are grouped together. + * + * Use XPLMNavRef to refer to a nav-aid. + * + * XPLM_NAV_NOT_FOUND is returned by functions that return an XPLMNavRef when + * the iterator must be invalid. + * + */ +typedef int XPLMNavRef; + +#define XPLM_NAV_NOT_FOUND -1 + +/* + * XPLMGetFirstNavAid + * + * This returns the very first navaid in the database. Use this to traverse + * the entire database. Returns XPLM_NAV_NOT_FOUND if the nav database is + * empty. + * + */ +XPLM_API XPLMNavRef XPLMGetFirstNavAid(void); + +/* + * XPLMGetNextNavAid + * + * Given a valid nav aid ref, this routine returns the next navaid. It + * returns XPLM_NAV_NOT_FOUND if the nav aid passed in was invalid or if the + * navaid passed in was the last one in the database. Use this routine to + * iterate across all like-typed navaids or the entire database. + * + */ +XPLM_API XPLMNavRef XPLMGetNextNavAid( + XPLMNavRef inNavAidRef); + +/* + * XPLMFindFirstNavAidOfType + * + * This routine returns the ref of the first navaid of the given type in the + * database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + * database. You must pass exactly one nav aid type to this routine. + * + */ +XPLM_API XPLMNavRef XPLMFindFirstNavAidOfType( + XPLMNavType inType); + +/* + * XPLMFindLastNavAidOfType + * + * This routine returns the ref of the last navaid of the given type in the + * database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + * database. You must pass exactly one nav aid type to this routine. + * + */ +XPLM_API XPLMNavRef XPLMFindLastNavAidOfType( + XPLMNavType inType); + +/* + * XPLMFindNavAid + * + * This routine provides a number of searching capabilities for the nav + * database. XPLMFindNavAid will search through every nav aid whose type is + * within inType (multiple types may be added together) and return any + * nav-aids found based on the following rules: + * + * * If inLat and inLon are not NULL, the navaid nearest to that lat/lon will + * be returned, otherwise the last navaid found will be returned. + * + * * If inFrequency is not NULL, then any navaids considered must match this + * frequency. Note that this will screen out radio beacons that do not have + * frequency data published (like inner markers) but not fixes and airports. + * + * * If inNameFragment is not NULL, only navaids that contain the fragment in + * their name will be returned. + * + * * If inIDFragment is not NULL, only navaids that contain the fragment in + * their IDs will be returned. + * + * This routine provides a simple way to do a number of useful searches: + * * Find the nearest navaid on this frequency. + * * Find the nearest airport. + * * Find the VOR whose ID is "KBOS". + * * Find the nearest airport whose name contains "Chicago". + * + */ +XPLM_API XPLMNavRef XPLMFindNavAid( + const char * inNameFragment, /* Can be NULL */ + const char * inIDFragment, /* Can be NULL */ + float * inLat, /* Can be NULL */ + float * inLon, /* Can be NULL */ + int * inFrequency, /* Can be NULL */ + XPLMNavType inType); + +/* + * XPLMGetNavAidInfo + * + * This routine returns information about a navaid. Any non-null field is + * filled out with information if it is available. + * + * Frequencies are in the nav.dat convention as described in the X-Plane nav + * database FAQ: NDB frequencies are exact, all others are multiplied by 100. + * + * The buffer for IDs should be at least 6 chars and the buffer for names + * should be at least 41 chars, but since these values are likely to go up, I + * recommend passing at least 32 chars for IDs and 256 chars for names when + * possible. + * + * The outReg parameter tells if the navaid is within the local "region" of + * loaded DSFs. (This information may not be particularly useful to plugins.) + * The parameter is a single byte value 1 for true or 0 for false, not a C + * string. + * + */ +XPLM_API void XPLMGetNavAidInfo( + XPLMNavRef inRef, + XPLMNavType * outType, /* Can be NULL */ + float * outLatitude, /* Can be NULL */ + float * outLongitude, /* Can be NULL */ + float * outHeight, /* Can be NULL */ + int * outFrequency, /* Can be NULL */ + float * outHeading, /* Can be NULL */ + char * outID, /* Can be NULL */ + char * outName, /* Can be NULL */ + char * outReg); /* Can be NULL */ + +/*************************************************************************** + * FLIGHT MANAGEMENT COMPUTER + ***************************************************************************/ +/* + * Note: the FMS works based on an array of entries. Indices into the array + * are zero-based. Each entry is a nav-aid plus an altitude. The FMS tracks + * the currently displayed entry and the entry that it is flying to. + * + * The FMS must be programmed with contiguous entries, so clearing an entry at + * the end shortens the effective flight plan. There is a max of 100 + * waypoints in the flight plan. + * + */ + + +/* + * XPLMCountFMSEntries + * + * This routine returns the number of entries in the FMS. + * + */ +XPLM_API int XPLMCountFMSEntries(void); + +/* + * XPLMGetDisplayedFMSEntry + * + * This routine returns the index of the entry the pilot is viewing. + * + */ +XPLM_API int XPLMGetDisplayedFMSEntry(void); + +/* + * XPLMGetDestinationFMSEntry + * + * This routine returns the index of the entry the FMS is flying to. + * + */ +XPLM_API int XPLMGetDestinationFMSEntry(void); + +/* + * XPLMSetDisplayedFMSEntry + * + * This routine changes which entry the FMS is showing to the index specified. + * + */ +XPLM_API void XPLMSetDisplayedFMSEntry( + int inIndex); + +/* + * XPLMSetDestinationFMSEntry + * + * This routine changes which entry the FMS is flying the aircraft toward. + * + */ +XPLM_API void XPLMSetDestinationFMSEntry( + int inIndex); + +/* + * XPLMGetFMSEntryInfo + * + * This routine returns information about a given FMS entry. If the entry is + * an airport or navaid, a reference to a nav entry can be returned allowing + * you to find additional information (such as a frequency, ILS heading, name, + * etc.). Note that this reference can be XPLM_NAV_NOT_FOUND until the + * information has been looked up asynchronously, so after flightplan changes, + * it might take up to a second for this field to become populated. The other + * information is available immediately. For a lat/lon entry, the lat/lon is + * returned by this routine but the navaid cannot be looked up (and the + * reference will be XPLM_NAV_NOT_FOUND). FMS name entry buffers should be at + * least 256 chars in length. + * + * WARNING: Due to a bug in X-Plane prior to 11.31, the navaid reference will + * not be set to XPLM_NAV_NOT_FOUND while no data is available, and instead + * just remain the value of the variable that you passed the pointer to. + * Therefore, always initialize the variable to XPLM_NAV_NOT_FOUND before + * passing the pointer to this function. + * + */ +XPLM_API void XPLMGetFMSEntryInfo( + int inIndex, + XPLMNavType * outType, /* Can be NULL */ + char * outID, /* Can be NULL */ + XPLMNavRef * outRef, /* Can be NULL */ + int * outAltitude, /* Can be NULL */ + float * outLat, /* Can be NULL */ + float * outLon); /* Can be NULL */ + +/* + * XPLMSetFMSEntryInfo + * + * This routine changes an entry in the FMS to have the destination navaid + * passed in and the altitude specified. Use this only for airports, fixes, + * and radio-beacon navaids. Currently of radio beacons, the FMS can only + * support VORs and NDBs. Use the routines below to clear or fly to a lat/lon. + * + */ +XPLM_API void XPLMSetFMSEntryInfo( + int inIndex, + XPLMNavRef inRef, + int inAltitude); + +/* + * XPLMSetFMSEntryLatLon + * + * This routine changes the entry in the FMS to a lat/lon entry with the given + * coordinates. + * + */ +XPLM_API void XPLMSetFMSEntryLatLon( + int inIndex, + float inLat, + float inLon, + int inAltitude); + +/* + * XPLMClearFMSEntry + * + * This routine clears the given entry, potentially shortening the flight + * plan. + * + */ +XPLM_API void XPLMClearFMSEntry( + int inIndex); + +/*************************************************************************** + * GPS RECEIVER + ***************************************************************************/ +/* + * These APIs let you read data from the GPS unit. + * + */ + +/* + * XPLMGetGPSDestinationType + * + * This routine returns the type of the currently selected GPS destination, + * one of fix, airport, VOR or NDB. + * + */ +XPLM_API XPLMNavType XPLMGetGPSDestinationType(void); + +/* + * XPLMGetGPSDestination + * + * This routine returns the current GPS destination. + * + */ +XPLM_API XPLMNavRef XPLMGetGPSDestination(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMPlanes.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMPlanes.h new file mode 100644 index 0000000..486302d --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMPlanes.h @@ -0,0 +1,287 @@ +#ifndef _XPLMPlanes_h_ +#define _XPLMPlanes_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMPlanes + ***************************************************************************/ +/* + * The XPLMPlanes APIs allow you to control the various aircraft in X-Plane, + * both the user's and the sim's. + * + * *Note*: unlike almost all other APIs in the SDK, aircraft paths are _full_ + * file system paths for historical reasons. You'll need to prefix all + * relative paths with the X-Plane path as accessed via XPLMGetSystemPath. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * USER AIRCRAFT ACCESS + ***************************************************************************/ + +/* + * XPLMSetUsersAircraft + * + * This routine changes the user's aircraft. Note that this will reinitialize + * the user to be on the nearest airport's first runway. Pass in a full path + * (hard drive and everything including the .acf extension) to the .acf file. + * + */ +XPLM_API void XPLMSetUsersAircraft( + const char * inAircraftPath); +/* + * XPLMPlaceUserAtAirport + * + * This routine places the user at a given airport. Specify the airport by + * its X-Plane airport ID (e.g. 'KBOS'). + * + */ +XPLM_API void XPLMPlaceUserAtAirport( + const char * inAirportCode); +#if defined(XPLM300) +/* + * XPLMPlaceUserAtLocation + * + * Places the user at a specific location after performing any necessary + * scenery loads. + * + * As with in-air starts initiated from the X-Plane user interface, the + * aircraft will always start with its engines running, regardless of the + * user's preferences (i.e., regardless of what the dataref + * `sim/operation/prefs/startup_running` says). + * + */ +XPLM_API void XPLMPlaceUserAtLocation( + double latitudeDegrees, + double longitudeDegrees, + float elevationMetersMSL, + float headingDegreesTrue, + float speedMetersPerSecond); +#endif /* XPLM300 */ +/*************************************************************************** + * GLOBAL AIRCRAFT ACCESS + ***************************************************************************/ + +/* The user's aircraft is always index 0. */ +#define XPLM_USER_AIRCRAFT 0 +#if defined(XPLM_DEPRECATED) +/* + * XPLMPlaneDrawState_t + * + * This structure contains additional plane parameter info to be passed to + * draw plane. Make sure to fill in the size of the structure field with + * sizeof(XPLMDrawPlaneState_t) so that the XPLM can tell how many fields you + * knew about when compiling your plugin (since more fields may be added + * later). + * + * Most of these fields are ratios from 0 to 1 for control input. X-Plane + * calculates what the actual controls look like based on the .acf file for + * that airplane. Note for the yoke inputs, this is what the pilot of the + * plane has commanded (post artificial stability system if there were one) + * and affects aelerons, rudder, etc. It is not necessarily related to the + * actual position of the plane! + * + */ +typedef struct { + /* The size of the draw state struct. */ + int structSize; + /* A ratio from [0..1] describing how far the landing gear is extended. */ + float gearPosition; + /* Ratio of flap deployment, 0 = up, 1 = full deploy. */ + float flapRatio; + /* Ratio of spoiler deployment, 0 = none, 1 = full deploy. */ + float spoilerRatio; + /* Ratio of speed brake deployment, 0 = none, 1 = full deploy. */ + float speedBrakeRatio; + /* Ratio of slat deployment, 0 = none, 1 = full deploy. */ + float slatRatio; + /* Wing sweep ratio, 0 = forward, 1 = swept. */ + float wingSweep; + /* Thrust power, 0 = none, 1 = full fwd, -1 = full reverse. */ + float thrust; + /* Total pitch input for this plane. */ + float yokePitch; + /* Total Heading input for this plane. */ + float yokeHeading; + /* Total Roll input for this plane. */ + float yokeRoll; +} XPLMPlaneDrawState_t; +#endif /* XPLM_DEPRECATED */ +/* + * XPLMCountAircraft + * + * This function returns the number of aircraft X-Plane is capable of having, + * as well as the number of aircraft that are currently active. These numbers + * count the user's aircraft. It can also return the plugin that is currently + * controlling aircraft. In X-Plane 7, this routine reflects the number of + * aircraft the user has enabled in the rendering options window. + * + */ +XPLM_API void XPLMCountAircraft( + int * outTotalAircraft, + int * outActiveAircraft, + XPLMPluginID * outController); +/* + * XPLMGetNthAircraftModel + * + * This function returns the aircraft model for the Nth aircraft. Indices are + * zero based, with zero being the user's aircraft. The file name should be + * at least 256 chars in length; the path should be at least 512 chars in + * length. + * + */ +XPLM_API void XPLMGetNthAircraftModel( + int inIndex, + char * outFileName, + char * outPath); +/*************************************************************************** + * EXCLUSIVE AIRCRAFT ACCESS + ***************************************************************************/ +/* + * The following routines require exclusive access to the airplane APIs. Only + * one plugin may have this access at a time. + * + */ + + +/* + * XPLMPlanesAvailable_f + * + * Your airplanes available callback is called when another plugin gives up + * access to the multiplayer planes. Use this to wait for access to + * multiplayer. + * + */ +typedef void (* XPLMPlanesAvailable_f)( + void * inRefcon); + +/* + * XPLMAcquirePlanes + * + * XPLMAcquirePlanes grants your plugin exclusive access to the aircraft. It + * returns 1 if you gain access, 0 if you do not. + * + * inAircraft - pass in an array of pointers to strings specifying the planes + * you want loaded. For any plane index you do not want loaded, pass a + * 0-length string. Other strings should be full paths with the .acf + * extension. NULL terminates this array, or pass NULL if there are no planes + * you want loaded. + * + * If you pass in a callback and do not receive access to the planes your + * callback will be called when the airplanes are available. If you do receive + * airplane access, your callback will not be called. + * + */ +XPLM_API int XPLMAcquirePlanes( + char ** inAircraft, /* Can be NULL */ + XPLMPlanesAvailable_f inCallback, + void * inRefcon); + +/* + * XPLMReleasePlanes + * + * Call this function to release access to the planes. Note that if you are + * disabled, access to planes is released for you and you must reacquire it. + * + */ +XPLM_API void XPLMReleasePlanes(void); + +/* + * XPLMSetActiveAircraftCount + * + * This routine sets the number of active planes. If you pass in a number + * higher than the total number of planes availables, only the total number of + * planes available is actually used. + * + */ +XPLM_API void XPLMSetActiveAircraftCount( + int inCount); + +/* + * XPLMSetAircraftModel + * + * This routine loads an aircraft model. It may only be called if you have + * exclusive access to the airplane APIs. Pass in the path of the model with + * the .acf extension. The index is zero based, but you may not pass in 0 + * (use XPLMSetUsersAircraft to load the user's aircracft). + * + */ +XPLM_API void XPLMSetAircraftModel( + int inIndex, + const char * inAircraftPath); + +/* + * XPLMDisableAIForPlane + * + * This routine turns off X-Plane's AI for a given plane. The plane will + * continue to draw and be a real plane in X-Plane, but will not move itself. + * + */ +XPLM_API void XPLMDisableAIForPlane( + int inPlaneIndex); + +#if defined(XPLM_DEPRECATED) +/* + * XPLMDrawAircraft + * + * WARNING: Aircraft drawing via this API is deprecated and will not work in + * future versions of X-Plane. Use XPLMInstance for 3-d drawing of custom + * aircraft models. + * + * This routine draws an aircraft. It can only be called from a 3-d drawing + * callback. Pass in the position of the plane in OpenGL local coordinates + * and the orientation of the plane. A 1 for full drawing indicates that the + * whole plane must be drawn; a 0 indicates you only need the nav lights + * drawn. (This saves rendering time when planes are far away.) + * + */ +XPLM_API void XPLMDrawAircraft( + int inPlaneIndex, + float inX, + float inY, + float inZ, + float inPitch, + float inRoll, + float inYaw, + int inFullDraw, + XPLMPlaneDrawState_t * inDrawStateInfo); +#endif /* XPLM_DEPRECATED */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMReinitUsersPlane + * + * WARNING: DO NOT USE. Use XPLMPlaceUserAtAirport or + * XPLMPlaceUserAtLocation. + * + * This function recomputes the derived flight model data from the aircraft + * structure in memory. If you have used the data access layer to modify the + * aircraft structure, use this routine to resynchronize X-Plane; since + * X-Plane works at least partly from derived values, the sim will not behave + * properly until this is called. + * + * WARNING: this routine does not necessarily place the airplane at the + * airport; use XPLMSetUsersAircraft to be compatible. This routine is + * provided to do special experimentation with flight models without resetting + * flight. + * + */ +XPLM_API void XPLMReinitUsersPlane(void); +#endif /* XPLM_DEPRECATED */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMPlugin.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMPlugin.h new file mode 100644 index 0000000..be5d06c --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMPlugin.h @@ -0,0 +1,422 @@ +#ifndef _XPLMPlugin_h_ +#define _XPLMPlugin_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMPlugin + ***************************************************************************/ +/* + * These APIs provide facilities to find and work with other plugins and + * manage other plugins. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FINDING PLUGINS + ***************************************************************************/ +/* + * These APIs allow you to find another plugin or yourself, or iterate across + * all plugins. For example, if you wrote an FMS plugin that needed to talk + * to an autopilot plugin, you could use these APIs to locate the autopilot + * plugin. + * + */ + + +/* + * XPLMGetMyID + * + * This routine returns the plugin ID of the calling plug-in. Call this to + * get your own ID. + * + */ +XPLM_API XPLMPluginID XPLMGetMyID(void); + +/* + * XPLMCountPlugins + * + * This routine returns the total number of plug-ins that are loaded, both + * disabled and enabled. + * + */ +XPLM_API int XPLMCountPlugins(void); + +/* + * XPLMGetNthPlugin + * + * This routine returns the ID of a plug-in by index. Index is 0 based from 0 + * to XPLMCountPlugins-1, inclusive. Plugins may be returned in any arbitrary + * order. + * + */ +XPLM_API XPLMPluginID XPLMGetNthPlugin( + int inIndex); + +/* + * XPLMFindPluginByPath + * + * This routine returns the plug-in ID of the plug-in whose file exists at the + * passed in absolute file system path. XPLM_NO_PLUGIN_ID is returned if the + * path does not point to a currently loaded plug-in. + * + */ +XPLM_API XPLMPluginID XPLMFindPluginByPath( + const char * inPath); + +/* + * XPLMFindPluginBySignature + * + * This routine returns the plug-in ID of the plug-in whose signature matches + * what is passed in or XPLM_NO_PLUGIN_ID if no running plug-in has this + * signature. Signatures are the best way to identify another plug-in as they + * are independent of the file system path of a plug-in or the human-readable + * plug-in name, and should be unique for all plug-ins. Use this routine to + * locate another plugin that your plugin interoperates with + * + */ +XPLM_API XPLMPluginID XPLMFindPluginBySignature( + const char * inSignature); + +/* + * XPLMGetPluginInfo + * + * This routine returns information about a plug-in. Each parameter should be + * a pointer to a buffer of at least + * 256 characters, or NULL to not receive the information. + * + * outName - the human-readable name of the plug-in. outFilePath - the + * absolute file path to the file that contains this plug-in. outSignature - a + * unique string that identifies this plug-in. outDescription - a + * human-readable description of this plug-in. + * + */ +XPLM_API void XPLMGetPluginInfo( + XPLMPluginID inPlugin, + char * outName, /* Can be NULL */ + char * outFilePath, /* Can be NULL */ + char * outSignature, /* Can be NULL */ + char * outDescription); /* Can be NULL */ + +/*************************************************************************** + * ENABLING/DISABLING PLUG-INS + ***************************************************************************/ +/* + * These routines are used to work with plug-ins and manage them. Most + * plugins will not need to use these APIs. + * + */ + + +/* + * XPLMIsPluginEnabled + * + * Returns whether the specified plug-in is enabled for running. + * + */ +XPLM_API int XPLMIsPluginEnabled( + XPLMPluginID inPluginID); + +/* + * XPLMEnablePlugin + * + * This routine enables a plug-in if it is not already enabled. It returns 1 + * if the plugin was enabled or successfully enables itself, 0 if it does not. + * Plugins may fail to enable (for example, if resources cannot be acquired) + * by returning 0 from their XPluginEnable callback. + * + */ +XPLM_API int XPLMEnablePlugin( + XPLMPluginID inPluginID); + +/* + * XPLMDisablePlugin + * + * This routine disableds an enabled plug-in. + * + */ +XPLM_API void XPLMDisablePlugin( + XPLMPluginID inPluginID); + +/* + * XPLMReloadPlugins + * + * This routine reloads all plug-ins. Once this routine is called and you + * return from the callback you were within (e.g. a menu select callback) you + * will receive your XPluginDisable and XPluginStop callbacks and your DLL + * will be unloaded, then the start process happens as if the sim was starting + * up. + * + */ +XPLM_API void XPLMReloadPlugins(void); + +/*************************************************************************** + * INTERPLUGIN MESSAGING + ***************************************************************************/ +/* + * Plugin messages are defined as 32-bit integers. Messages below 0x00FFFFFF + * are reserved for X-Plane and the plugin SDK. + * + * Messages come with a pointer parameter; the meaning of this pointer depends + * on the message itself. In some messages, the pointer parameter contains an + * actual typed pointer to data that can be inspected in the plugin; in these + * cases the documentation will state that the parameter "points to" + * information. + * + * in other cases, the value of the pointer is actually an integral number + * stuffed into the pointer's storage. In these second cases, the pointer + * parameter needs to be cast, not dereferenced. In these caess, the + * documentation will state that the parameter "contains" a value, which will + * always be an integral type. + * + * Some messages don't use the pointer parameter - in this case your plugin + * should ignore it. + * + * Messages have two conceptual uses: notifications and commands. Commands + * are sent from one plugin to another to induce behavior; notifications are + * sent from one plugin to all others for informational purposes. It is + * important that commands and notifications not have the same values because + * this could cause a notification sent by one plugin to accidentally induce a + * command in another. + * + * By convention, plugin-defined notifications should have the high bit set + * (e.g. be greater or equal to unsigned 0x8000000) while commands should have + * this bit be cleared. + * + * The following messages are sent to your plugin by X-Plane. + * + */ + + +/* This message is sent to your plugin whenever the user's plane crashes. The * + * parameter is ignored. */ +#define XPLM_MSG_PLANE_CRASHED 101 + +/* This message is sent to your plugin whenever a new plane is loaded. The * + * parameter contains the index number of the plane being loaded; 0 indicates * + * the user's plane. */ +#define XPLM_MSG_PLANE_LOADED 102 + +/* This messages is sent whenever the user's plane is positioned at a new * + * airport. The parameter is ignored. */ +#define XPLM_MSG_AIRPORT_LOADED 103 + +/* This message is sent whenever new scenery is loaded. Use datarefs to * + * determine the new scenery files that were loaded. The parameter is ignored.*/ +#define XPLM_MSG_SCENERY_LOADED 104 + +/* This message is sent whenever the user adjusts the number of X-Plane * + * aircraft models. You must use XPLMCountPlanes to find out how many planes * + * are now available. This message will only be sent in XP7 and higher * + * because in XP6 the number of aircraft is not user-adjustable. The parameter* + * is ignored. */ +#define XPLM_MSG_AIRPLANE_COUNT_CHANGED 105 + +#if defined(XPLM200) +/* This message is sent to your plugin whenever a plane is unloaded. The * + * parameter contains the index number of the plane being unloaded; 0 * + * indicates the user's plane. The parameter is of type int, passed as the * + * value of the pointer. (That is: the parameter is an int, not a pointer to * + * an int.) */ +#define XPLM_MSG_PLANE_UNLOADED 106 +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* This message is sent to your plugin right before X-Plane writes its * + * preferences file. You can use this for two purposes: to write your own * + * preferences, and to modify any datarefs to influence preferences output. * + * For example, if your plugin temporarily modifies saved preferences, you can* + * put them back to their default values here to avoid having the tweaks be * + * persisted if your plugin is not loaded on the next invocation of X-Plane. * + * The parameter is ignored. */ +#define XPLM_MSG_WILL_WRITE_PREFS 107 +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* This message is sent to your plugin right after a livery is loaded for an * + * airplane. You can use this to check the new livery (via datarefs) and * + * react accordingly. The parameter contains the index number of the aircraft* + * whose livery is changing. */ +#define XPLM_MSG_LIVERY_LOADED 108 +#endif /* XPLM210 */ + +#if defined(XPLM301) +/* Sent to your plugin right before X-Plane enters virtual reality mode (at * + * which time any windows that are not positioned in VR mode will no longer be* + * visible to the user). The parameter is unused and should be ignored. */ +#define XPLM_MSG_ENTERED_VR 109 +#endif /* XPLM301 */ + +#if defined(XPLM301) +/* Sent to your plugin right before X-Plane leaves virtual reality mode (at * + * which time you may want to clean up windows that are positioned in VR * + * mode). The parameter is unused and should be ignored. */ +#define XPLM_MSG_EXITING_VR 110 +#endif /* XPLM301 */ + +#if defined(XPLM303) +/* Sent to your plugin if another plugin wants to take over AI planes. If you * + * are a synthetic traffic provider, that probably means a plugin for an * + * online network has connected and wants to supply aircraft flown by real * + * humans and you should cease to provide synthetic traffic. If however you * + * are providing online traffic from real humans, you probably don't want to * + * disconnect, in which case you just ignore this message. The sender is the * + * plugin ID of the plugin asking for control of the planes now. You can use * + * it to find out who is requesting and whether you should yield to them. * + * Synthetic traffic providers should always yield to online networks. The * + * parameter is unused and should be ignored. */ +#define XPLM_MSG_RELEASE_PLANES 111 +#endif /* XPLM303 */ + +/* + * XPLMSendMessageToPlugin + * + * This function sends a message to another plug-in or X-Plane. Pass + * XPLM_NO_PLUGIN_ID to broadcast to all plug-ins. Only enabled plug-ins with + * a message receive function receive the message. + * + */ +XPLM_API void XPLMSendMessageToPlugin( + XPLMPluginID inPlugin, + int inMessage, + void * inParam); + +#if defined(XPLM200) +/*************************************************************************** + * Plugin Features API + ***************************************************************************/ +/* + * The plugin features API allows your plugin to "sign up" for additional + * capabilities and plugin system features that are normally disabled for + * backward compatibility. This allows advanced plugins to "opt-in" to new + * behavior. + * + * Each feature is defined by a permanent string name. The feature string + * names will vary with the particular installation of X-Plane, so plugins + * should not expect a feature to be guaranteed present. + * + * XPLM_WANTS_REFLECTIONS + * ---------------------- + * + * Available in the SDK 2.0 and later for X-Plane 9, enabling this capability + * causes your plugin to receive drawing hook callbacks when X-Plane builds + * its off-screen reflection and shadow rendering passes. Plugins should + * enable this and examine the dataref sim/graphics/view/plane_render_type to + * determine whether the drawing callback is for a reflection, shadow + * calculation, or the main screen. Rendering can be simlified or omitted for + * reflections, and non-solid drawing should be skipped for shadow + * calculations. + * + * **Note**: direct drawing via draw callbacks is not recommended; use the + * XPLMInstance API to create object models instead. + * + * XPLM_USE_NATIVE_PATHS + * --------------------- + * + * available in the SDK 2.1 and later for X-Plane 10, this modifies the plugin + * system to use Unix-style paths on all operating systems. With this enabled: + * + * * OS X paths will match the native OS X Unix. + * * Windows will use forward slashes but preserve C:\ or another drive letter + * when using complete file paths. + * * Linux uses its native file system path scheme. + * + * Without this enabled: + * + * * OS X will use CFM file paths separated by a colon. + * * Windows will use back-slashes and conventional DOS paths. + * * Linux uses its native file system path scheme. + * + * All plugins should enable this feature on OS X to access the native file + * system. + * + * XPLM_USE_NATIVE_WIDGET_WINDOWS + * ------------------------------ + * + * Available in the SDK 3.0.2 SDK, this capability tells the widgets library + * to use new, modern X-Plane backed XPLMDisplay windows to anchor all widget + * trees. Without it, widgets will always use legacy windows. + * + * Plugins should enable this to allow their widget hierarchies to respond to + * the user's UI size settings and to map widget-based windwos to a VR HMD. + * + * Before enabling this, make sure any custom widget code in your plugin is + * prepared to cope with the UI coordinate system not being th same as the + * OpenGL window coordinate system. + * + */ + + +/* + * XPLMFeatureEnumerator_f + * + * You pass an XPLMFeatureEnumerator_f to get a list of all features supported + * by a given version running version of X-Plane. This routine is called once + * for each feature. + * + */ +typedef void (* XPLMFeatureEnumerator_f)( + const char * inFeature, + void * inRef); + +/* + * XPLMHasFeature + * + * This returns 1 if the given installation of X-Plane supports a feature, or + * 0 if it does not. + * + */ +XPLM_API int XPLMHasFeature( + const char * inFeature); + +/* + * XPLMIsFeatureEnabled + * + * This returns 1 if a feature is currently enabled for your plugin, or 0 if + * it is not enabled. It is an error to call this routine with an unsupported + * feature. + * + */ +XPLM_API int XPLMIsFeatureEnabled( + const char * inFeature); + +/* + * XPLMEnableFeature + * + * This routine enables or disables a feature for your plugin. This will + * change the running behavior of X-Plane and your plugin in some way, + * depending on the feature. + * + */ +XPLM_API void XPLMEnableFeature( + const char * inFeature, + int inEnable); + +/* + * XPLMEnumerateFeatures + * + * This routine calls your enumerator callback once for each feature that this + * running version of X-Plane supports. Use this routine to determine all of + * the features that X-Plane can support. + * + */ +XPLM_API void XPLMEnumerateFeatures( + XPLMFeatureEnumerator_f inEnumerator, + void * inRef); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMProcessing.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMProcessing.h new file mode 100644 index 0000000..94ef0c4 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMProcessing.h @@ -0,0 +1,264 @@ +#ifndef _XPLMProcessing_h_ +#define _XPLMProcessing_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMProcessing + ***************************************************************************/ +/* + * This API allows you to get regular callbacks during the flight loop, the + * part of X-Plane where the plane's position calculates the physics of + * flight, etc. Use these APIs to accomplish periodic tasks like logging data + * and performing I/O. + * + * You can receive a callback either just before or just after the per-frame + * physics calculations happen - you can use post-FM callbacks to "patch" the + * flight model after it has run. + * + * If the user has set the number of flight model iterations per frame greater + * than one your plugin will _not_ see this; these integrations run on the + * sub-section of the flight model where iterations improve responsiveness + * (e.g. physical integration, not simple systems tracking) and are thus + * opaque to plugins. + * + * Flight loop scheduling, when scheduled by time, is scheduled by a "first + * callback after the deadline" schedule, e.g. your callbacks will always be + * slightly late to ensure that we don't run faster than your deadline. + * + * WARNING: Do NOT use these callbacks to draw! You cannot draw during flight + * loop callbacks. Use the drawing callbacks (see XPLMDisplay for more info) + * for graphics. (One exception: you can use a post-flight loop callback to + * update your own off-screen FBOs.) + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FLIGHT LOOP CALLBACKS + ***************************************************************************/ + +#if defined(XPLM210) +/* + * XPLMFlightLoopPhaseType + * + * You can register a flight loop callback to run either before or after the + * flight model is integrated by X-Plane. + * + */ +enum { + /* Your callback runs before X-Plane integrates the flight model. */ + xplm_FlightLoop_Phase_BeforeFlightModel = 0, + + /* Your callback runs after X-Plane integrates the flight model. */ + xplm_FlightLoop_Phase_AfterFlightModel = 1, + + +}; +typedef int XPLMFlightLoopPhaseType; +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMFlightLoopID + * + * This is an opaque identifier for a flight loop callback. You can use this + * identifier to easily track and remove your callbacks, or to use the new + * flight loop APIs. + * + */ +typedef void * XPLMFlightLoopID; +#endif /* XPLM210 */ + +/* + * XPLMFlightLoop_f + * + * This is your flight loop callback. Each time the flight loop is iterated + * through, you receive this call at the end. + * + * Flight loop callbacks receive a number of input timing parameters. These + * input timing parameters are not particularly useful; you may need to track + * your own timing data (e.g. by reading datarefs). The input parameters are: + * + * - inElapsedSinceLastCall: the wall time since your last callback. + * - inElapsedTimeSinceLastFlightLoop: the wall time since any flight loop was + * dispatched. + * - inCounter: a monotonically increasing counter, bumped once per flight + * loop dispatch from the sim. + * - inRefcon: your own ptr constant from when you regitered yor callback. + * + * Your return value controls when you will next be called. + * + * - Return 0 to stop receiving callbacks. + * - Pass a positive number to specify how many seconds until the next + * callback. (You will be called at or after this time, not before.) + * - Pass a negative number to specify how many loops must go by until you + * are called. For example, -1.0 means call me the very next loop. + * + * Try to run your flight loop as infrequently as is practical, and suspend it + * (using return value 0) when you do not need it; lots of flight loop + * callbacks that do nothing lowers X-Plane's frame rate. + * + * Your callback will NOT be unregistered if you return 0; it will merely be + * inactive. + * + */ +typedef float (* XPLMFlightLoop_f)( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon); + +#if defined(XPLM210) +/* + * XPLMCreateFlightLoop_t + * + * XPLMCreateFlightLoop_t contains the parameters to create a new flight loop + * callback. The strsucture can be expanded in future SDKs - always set + * structSize to the size of your structure in bytes. + * + */ +typedef struct { + int structSize; + XPLMFlightLoopPhaseType phase; + XPLMFlightLoop_f callbackFunc; + void * refcon; +} XPLMCreateFlightLoop_t; +#endif /* XPLM210 */ + +/* + * XPLMGetElapsedTime + * + * This routine returns the elapsed time since the sim started up in decimal + * seconds. This is a wall timer; it keeps counting upward even if the sim is + * pasued. + * + * __WARNING__: XPLMGetElapsedTime is not a very good timer! It lacks + * precision in both its data type and its source. Do not attempt to use it + * for timing critical applications like network multiplayer. + * + */ +XPLM_API float XPLMGetElapsedTime(void); + +/* + * XPLMGetCycleNumber + * + * This routine returns a counter starting at zero for each sim cycle + * computed/video frame rendered. + * + */ +XPLM_API int XPLMGetCycleNumber(void); + +/* + * XPLMRegisterFlightLoopCallback + * + * This routine registers your flight loop callback. Pass in a pointer to a + * flight loop function and a refcon. inInterval defines when you will be + * called. Pass in a positive number to specify seconds from registration time + * to the next callback. Pass in a negative number to indicate when you will + * be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to not be + * called; your callback will be inactive. + * + * (This legacy function only installs pre-flight-loop callbacks; use + * XPLMCreateFlightLoop for more control.) + * + */ +XPLM_API void XPLMRegisterFlightLoopCallback( + XPLMFlightLoop_f inFlightLoop, + float inInterval, + void * inRefcon); + +/* + * XPLMUnregisterFlightLoopCallback + * + * This routine unregisters your flight loop callback. Do NOT call it from + * your flight loop callback. Once your flight loop callback is unregistered, + * it will not be called again. + * + * Only use this on flight loops registered via + * XPLMRegisterFlightLoopCallback. + * + */ +XPLM_API void XPLMUnregisterFlightLoopCallback( + XPLMFlightLoop_f inFlightLoop, + void * inRefcon); + +/* + * XPLMSetFlightLoopCallbackInterval + * + * This routine sets when a callback will be called. Do NOT call it from your + * callback; use the return value of the callback to change your callback + * interval from inside your callback. + * + * inInterval is formatted the same way as in XPLMRegisterFlightLoopCallback; + * positive for seconds, negative for cycles, and 0 for deactivating the + * callback. If inRelativeToNow is 1, times are from the time of this call; + * otherwise they are from the time the callback was last called (or the time + * it was registered if it has never been called. + * + */ +XPLM_API void XPLMSetFlightLoopCallbackInterval( + XPLMFlightLoop_f inFlightLoop, + float inInterval, + int inRelativeToNow, + void * inRefcon); + +#if defined(XPLM210) +/* + * XPLMCreateFlightLoop + * + * This routine creates a flight loop callback and returns its ID. The flight + * loop callback is created using the input param struct, and is inited to be + * unscheduled. + * + */ +XPLM_API XPLMFlightLoopID XPLMCreateFlightLoop( + XPLMCreateFlightLoop_t * inParams); +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMDestroyFlightLoop + * + * This routine destroys a flight loop callback by ID. Only call it on flight + * loops created with the newer XPLMCreateFlightLoop API. + * + */ +XPLM_API void XPLMDestroyFlightLoop( + XPLMFlightLoopID inFlightLoopID); +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMScheduleFlightLoop + * + * This routine schedules a flight loop callback for future execution. If + * inInterval is negative, it is run in a certain number of frames based on + * the absolute value of the input. If the interval is positive, it is a + * duration in seconds. + * + * If inRelativeToNow is true, ties are interpretted relative to the time this + * routine is called; otherwise they are relative to the last call time or the + * time the flight loop was registered (if never called). + * + */ +XPLM_API void XPLMScheduleFlightLoop( + XPLMFlightLoopID inFlightLoopID, + float inInterval, + int inRelativeToNow); +#endif /* XPLM210 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMScenery.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMScenery.h new file mode 100644 index 0000000..452bac9 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMScenery.h @@ -0,0 +1,450 @@ +#ifndef _XPLMScenery_h_ +#define _XPLMScenery_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMScenery + ***************************************************************************/ +/* + * This package contains APIs to interact with X-Plane's scenery system. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XPLM200) +/*************************************************************************** + * Terrain Y-Testing + ***************************************************************************/ +/* + * The Y-testing API allows you to locate the physical scenery mesh. This + * would be used to place dynamic graphics on top of the ground in a plausible + * way or do physics interactions. + * + * The Y-test API works via probe objects, which are allocated by your plugin + * and used to query terrain. Probe objects exist both to capture which + * algorithm you have requested (see probe types) and also to cache query + * information. + * + * Performance Guidelines + * ---------------------- + * + * It is generally faster to use the same probe for nearby points and + * different probes for different points. Try not to allocate more than + * "hundreds" of probes at most. Share probes if you need more. Generally, + * probing operations are expensive, and should be avoided via caching when + * possible. + * + * Y testing returns a location on the terrain, a normal vectory, and a + * velocity vector. The normal vector tells you the slope of the terrain at + * that point. The velocity vector tells you if that terrain is moving (and is + * in meters/second). For example, if your Y test hits the aircraft carrier + * deck, this tells you the velocity of that point on the deck. + * + * Note: the Y-testing API is limited to probing the loaded scenery area, + * which is approximately 300x300 km in X-Plane 9. Probes outside this area + * will return the height of a 0 MSL sphere. + * + */ + + +/* + * XPLMProbeType + * + * XPLMProbeType defines the type of terrain probe - each probe has a + * different algorithm. (Only one type of probe is provided right now, but + * future APIs will expose more flexible or poewrful or useful probes. + * + */ +enum { + /* The Y probe gives you the location of the tallest physical scenery along * + * the Y axis going through the queried point. */ + xplm_ProbeY = 0, + + +}; +typedef int XPLMProbeType; + +/* + * XPLMProbeResult + * + * Probe results - possible results from a probe query. + * + */ +enum { + /* The probe hit terrain and returned valid values. */ + xplm_ProbeHitTerrain = 0, + + /* An error in the API call. Either the probe struct size is bad, or the * + * probe is invalid or the type is mismatched for the specific query call. */ + xplm_ProbeError = 1, + + /* The probe call succeeded but there is no terrain under this point (perhaps * + * it is off the side of the planet?) */ + xplm_ProbeMissed = 2, + + +}; +typedef int XPLMProbeResult; + +/* + * XPLMProbeRef + * + * An XPLMProbeRef is an opaque handle to a probe, used for querying the + * terrain. + * + */ +typedef void * XPLMProbeRef; + +/* + * XPLMProbeInfo_t + * + * XPLMProbeInfo_t contains the results of a probe call. Make sure to set + * structSize to the size of the struct before using it. + * + */ +typedef struct { + /* Size of structure in bytes - always set this before calling the XPLM. */ + int structSize; + /* Resulting X location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationX; + /* Resulting Y location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationY; + /* Resulting Z location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationZ; + /* X component of the normal vector to the terrain we found. */ + float normalX; + /* Y component of the normal vector to the terrain we found. */ + float normalY; + /* Z component of the normal vector to the terrain we found. */ + float normalZ; + /* X component of the velocity vector of the terrain we found. */ + float velocityX; + /* Y component of the velocity vector of the terrain we found. */ + float velocityY; + /* Z component of the velocity vector of the terrain we found. */ + float velocityZ; + /* Tells if the surface we hit is water (otherwise it is land). */ + int is_wet; +} XPLMProbeInfo_t; + +/* + * XPLMCreateProbe + * + * Creates a new probe object of a given type and returns. + * + */ +XPLM_API XPLMProbeRef XPLMCreateProbe( + XPLMProbeType inProbeType); + +/* + * XPLMDestroyProbe + * + * Deallocates an existing probe object. + * + */ +XPLM_API void XPLMDestroyProbe( + XPLMProbeRef inProbe); + +/* + * XPLMProbeTerrainXYZ + * + * Probes the terrain. Pass in the XYZ coordinate of the probe point, a probe + * object, and an XPLMProbeInfo_t struct that has its structSize member set + * properly. Other fields are filled in if we hit terrain, and a probe result + * is returned. + * + */ +XPLM_API XPLMProbeResult XPLMProbeTerrainXYZ( + XPLMProbeRef inProbe, + float inX, + float inY, + float inZ, + XPLMProbeInfo_t * outInfo); + +#endif /* XPLM200 */ +#if defined(XPLM300) +/*************************************************************************** + * Magnetic Variation + ***************************************************************************/ +/* + * Use the magnetic variation (more properly, the "magnetic declination") API + * to find the offset of magnetic north from true north at a given latitude + * and longitude within the simulator. + * + * In the real world, the Earth's magnetic field is irregular, such that true + * north (the direction along a meridian toward the north pole) does not + * necessarily match what a magnetic compass shows as north. + * + * Using this API ensures that you present the same offsets to users as + * X-Plane's built-in instruments. + * + */ + + +/* + * XPLMGetMagneticVariation + * + * Returns X-Plane's simulated magnetic variation (declination) at the + * indication latitude and longitude. + * + */ +XPLM_API float XPLMGetMagneticVariation( + double latitude, + double longitude); + +/* + * XPLMDegTrueToDegMagnetic + * + * Converts a heading in degrees relative to true north into a value relative + * to magnetic north at the user's current location. + * + */ +XPLM_API float XPLMDegTrueToDegMagnetic( + float headingDegreesTrue); + +/* + * XPLMDegMagneticToDegTrue + * + * Converts a heading in degrees relative to magnetic north at the user's + * current location into a value relative to true north. + * + */ +XPLM_API float XPLMDegMagneticToDegTrue( + float headingDegreesMagnetic); + +#endif /* XPLM300 */ +/*************************************************************************** + * Object Drawing + ***************************************************************************/ +/* + * The object drawing routines let you load and draw X-Plane OBJ files. + * Objects are loaded by file path and managed via an opaque handle. X-Plane + * naturally reference counts objects, so it is important that you balance + * every successful call to XPLMLoadObject with a call to XPLMUnloadObject! + * + */ + + +#if defined(XPLM200) +/* + * XPLMObjectRef + * + * An XPLMObjectRef is a opaque handle to an .obj file that has been loaded + * into memory. + * + */ +typedef void * XPLMObjectRef; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMDrawInfo_t + * + * The XPLMDrawInfo_t structure contains positioning info for one object that + * is to be drawn. Be sure to set structSize to the size of the structure for + * future expansion. + * + */ +typedef struct { + /* Set this to the size of this structure! */ + int structSize; + /* X location of the object in local coordinates. */ + float x; + /* Y location of the object in local coordinates. */ + float y; + /* Z location of the object in local coordinates. */ + float z; + /* Pitch in degres to rotate the object, positive is up. */ + float pitch; + /* Heading in local coordinates to rotate the object, clockwise. */ + float heading; + /* Roll to rotate the object. */ + float roll; +} XPLMDrawInfo_t; +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* + * XPLMObjectLoaded_f + * + * You provide this callback when loading an object asynchronously; it will be + * called once the object is loaded. Your refcon is passed back. The object + * ref passed in is the newly loaded object (ready for use) or NULL if an + * error occured. + * + * If your plugin is disabled, this callback will be delivered as soon as the + * plugin is re-enabled. If your plugin is unloaded before this callback is + * ever called, the SDK will release the object handle for you. + * + */ +typedef void (* XPLMObjectLoaded_f)( + XPLMObjectRef inObject, + void * inRefcon); +#endif /* XPLM210 */ + +#if defined(XPLM200) +/* + * XPLMLoadObject + * + * This routine loads an OBJ file and returns a handle to it. If X-Plane has + * already loaded the object, the handle to the existing object is returned. + * Do not assume you will get the same handle back twice, but do make sure to + * call unload once for every load to avoid "leaking" objects. The object will + * be purged from memory when no plugins and no scenery are using it. + * + * The path for the object must be relative to the X-System base folder. If + * the path is in the root of the X-System folder you may need to prepend ./ + * to it; loading objects in the root of the X-System folder is STRONGLY + * discouraged - your plugin should not dump art resources in the root folder! + * + * XPLMLoadObject will return NULL if the object cannot be loaded (either + * because it is not found or the file is misformatted). This routine will + * load any object that can be used in the X-Plane scenery system. + * + * It is important that the datarefs an object uses for animation already be + * loaded before you load the object. For this reason it may be necessary to + * defer object loading until the sim has fully started. + * + */ +XPLM_API XPLMObjectRef XPLMLoadObject( + const char * inPath); +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* + * XPLMLoadObjectAsync + * + * This routine loads an object asynchronously; control is returned to you + * immediately while X-Plane loads the object. The sim will not stop flying + * while the object loads. For large objects, it may be several seconds before + * the load finishes. + * + * You provide a callback function that is called once the load has completed. + * Note that if the object cannot be loaded, you will not find out until the + * callback function is called with a NULL object handle. + * + * There is no way to cancel an asynchronous object load; you must wait for + * the load to complete and then release the object if it is no longer + * desired. + * + */ +XPLM_API void XPLMLoadObjectAsync( + const char * inPath, + XPLMObjectLoaded_f inCallback, + void * inRefcon); +#endif /* XPLM210 */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMDrawObjects + * + * __Deprecation Warning__: use XPLMInstancing to draw 3-d objects by creating + * instances, rather than these APIs from draw callbacks. + * + * XPLMDrawObjects draws an object from an OBJ file one or more times. You + * pass in the object and an array of XPLMDrawInfo_t structs, one for each + * place you would like the object to be drawn. + * + * X-Plane will attempt to cull the objects based on LOD and visibility, and + * will pick the appropriate LOD. + * + * Lighting is a boolean; pass 1 to show the night version of object with + * night-only lights lit up. Pass 0 to show the daytime version of the object. + * + * earth_relative controls the coordinate system. If this is 1, the rotations + * you specify are applied to the object after its coordinate system is + * transformed from local to earth-relative coordinates -- that is, an object + * with no rotations will point toward true north and the Y axis will be up + * against gravity. If this is 0, the object is drawn with your rotations from + * local coordanates -- that is, an object with no rotations is drawn pointing + * down the -Z axis and the Y axis of the object matches the local coordinate + * Y axis. + * + */ +XPLM_API void XPLMDrawObjects( + XPLMObjectRef inObject, + int inCount, + XPLMDrawInfo_t * inLocations, + int lighting, + int earth_relative); +#endif /* XPLM_DEPRECATED */ + +#if defined(XPLM200) +/* + * XPLMUnloadObject + * + * This routine marks an object as no longer being used by your plugin. + * Objects are reference counted: once no plugins are using an object, it is + * purged from memory. Make sure to call XPLMUnloadObject once for each + * successful call to XPLMLoadObject. + * + */ +XPLM_API void XPLMUnloadObject( + XPLMObjectRef inObject); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/*************************************************************************** + * Library Access + ***************************************************************************/ +/* + * The library access routines allow you to locate scenery objects via the + * X-Plane library system. Right now library access is only provided for + * objects, allowing plugin-drawn objects to be extended using the library + * system. + * + */ + + +/* + * XPLMLibraryEnumerator_f + * + * An XPLMLibraryEnumerator_f is a callback you provide that is called once + * for each library element that is located. The returned paths will be + * relative to the X-System folder. + * + */ +typedef void (* XPLMLibraryEnumerator_f)( + const char * inFilePath, + void * inRef); + +/* + * XPLMLookupObjects + * + * This routine looks up a virtual path in the library system and returns all + * matching elements. You provide a callback - one virtual path may match many + * objects in the library. XPLMLookupObjects returns the number of objects + * found. + * + * The latitude and longitude parameters specify the location the object will + * be used. The library system allows for scenery packages to only provide + * objects to certain local locations. Only objects that are allowed at the + * latitude/longitude you provide will be returned. + * + */ +XPLM_API int XPLMLookupObjects( + const char * inPath, + float inLatitude, + float inLongitude, + XPLMLibraryEnumerator_f enumerator, + void * ref); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMUtilities.h b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMUtilities.h new file mode 100644 index 0000000..bec319e --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/CHeaders/XPLM/XPLMUtilities.h @@ -0,0 +1,970 @@ +#ifndef _XPLMUtilities_h_ +#define _XPLMUtilities_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMUtilities + ***************************************************************************/ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FILE UTILITIES + ***************************************************************************/ +/* + * The XPLMUtilities file APIs provide some basic file and path functions for + * use with X-Plane. + * + * Directory Separators + * -------------------- + * + * The XPLM has two modes it can work in: + * + * * X-Plane native paths: all paths are UTF8 strings, using the unix forward + * slash (/) as the directory separating character. In native path mode, + * you use the same path format for all three operating systems. + * + * * Legacy OS paths: the directroy separator is \ for Windows, : for OS X, + * and / for Linux; OS paths are encoded in MacRoman for OS X using legacy + * HFS conventions, use the application code page for multi-byte encoding + * on Unix using DOS path conventions, and use UTF-8 for Linux. + * + * While legacy OS paths are the default, we strongly encourage you to opt in + * to native paths using the XPLMEnableFeature API. + * + * * All OS X plugins should enable native paths all of the time; if you do + * not do this, you will have to convert all paths back from HFS to Unix + * (and deal with MacRoman) - code written using native paths and the C + * file APIs "just works" on OS X. + * + * * For Linux plugins, there is no difference between the two encodings. + * + * * Windows plugins will need to convert the UTF8 file paths to UTF16 for + * use with the "wide" APIs. While it might seem tempting to stick with + * legacy OS paths (and just use the "ANSI" Windows APIs), X-Plane is fully + * unicode-capable, and will often be installed in paths where the user's + * directories have no ACP encoding. + * + * Full and Relative Paths + * ----------------------- + * + * Some of these APIs use full paths, but others use paths relative to the + * user's X-Plane installation. This is documented on a per-API basis. + * + */ + + +#if defined(XPLM200) +/* + * XPLMDataFileType + * + * These enums define types of data files you can load or unload using the + * SDK. + * + */ +enum { + /* A situation (.sit) file, which starts off a flight in a given * + * configuration. */ + xplm_DataFile_Situation = 1, + + /* A situation movie (.smo) file, which replays a past flight. */ + xplm_DataFile_ReplayMovie = 2, + + +}; +typedef int XPLMDataFileType; +#endif /* XPLM200 */ + +/* + * XPLMGetSystemPath + * + * This function returns the full path to the X-System folder. Note that this + * is a directory path, so it ends in a trailing : or /. + * + * The buffer you pass should be at least 512 characters long. The path is + * returned using the current native or OS path conventions. + * + */ +XPLM_API void XPLMGetSystemPath( + char * outSystemPath); + +/* + * XPLMGetPrefsPath + * + * This routine returns a full path to a file that is within X-Plane's + * preferences directory. (You should remove the file name back to the last + * directory separator to get the preferences directory using + * XPLMExtractFileAndPath.) + * + * The buffer you pass should be at least 512 characters long. The path is + * returned using the current native or OS path conventions. + * + */ +XPLM_API void XPLMGetPrefsPath( + char * outPrefsPath); + +/* + * XPLMGetDirectorySeparator + * + * This routine returns a string with one char and a null terminator that is + * the directory separator for the current platform. This allows you to write + * code that concatinates directory paths without having to #ifdef for + * platform. The character returned will reflect the current file path mode. + * + */ +XPLM_API const char * XPLMGetDirectorySeparator(void); + +/* + * XPLMExtractFileAndPath + * + * Given a full path to a file, this routine separates the path from the file. + * If the path is a partial directory (e.g. ends in : or \) the trailing + * directory separator is removed. This routine works in-place; a pointer to + * the file part of the buffer is returned; the original buffer still starts + * with the path and is null terminated with no trailing separator. + * + */ +XPLM_API char * XPLMExtractFileAndPath( + char * inFullPath); + +/* + * XPLMGetDirectoryContents + * + * This routine returns a list of files in a directory (specified by a full + * path, no trailing : or \). The output is returned as a list of NULL + * terminated strings. An index array (if specified) is filled with pointers + * into the strings. The last file is indicated by a zero-length string (and + * NULL in the indices). This routine will return 1 if you had capacity for + * all files or 0 if you did not. You can also skip a given number of files. + * + * * inDirectoryPath - a null terminated C string containing the full path to + * the directory with no trailing directory char. + * + * * inFirstReturn - the zero-based index of the first file in the directory + * to return. (Usually zero to fetch all in one pass.) + * + * * outFileNames - a buffer to receive a series of sequential null + * terminated C-string file names. A zero-length C string will be appended + * to the very end. + * + * * inFileNameBufSize - the size of the file name buffer in bytes. + * + * * outIndices - a pointer to an array of character pointers that will + * become an index into the directory. The last file will be followed by a + * NULL value. Pass NULL if you do not want indexing information. + * + * * inIndexCount - the max size of the index in entries. + * + * * outTotalFiles - if not NULL, this is filled in with the number of files + * in the directory. + * + * * outReturnedFiles - if not NULL, the number of files returned by this + * iteration. + * + * Return value: 1 if all info could be returned, 0 if there was a buffer + * overrun. + * + * WARNING: Before X-Plane 7 this routine did not properly iterate through + * directories. If X-Plane + * 6 compatibility is needed, use your own code to iterate directories. + * + */ +XPLM_API int XPLMGetDirectoryContents( + const char * inDirectoryPath, + int inFirstReturn, + char * outFileNames, + int inFileNameBufSize, + char ** outIndices, /* Can be NULL */ + int inIndexCount, + int * outTotalFiles, /* Can be NULL */ + int * outReturnedFiles); /* Can be NULL */ + +#if defined(XPLM200) +/* + * XPLMLoadDataFile + * + * Loads a data file of a given type. Paths must be relative to the X-System + * folder. To clear the replay, pass a NULL file name (this is only valid with + * replay movies, not sit files). + * + */ +XPLM_API int XPLMLoadDataFile( + XPLMDataFileType inFileType, + const char * inFilePath); /* Can be NULL */ +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMSaveDataFile + * + * Saves the current situation or replay; paths are relative to the X-System + * folder. + * + */ +XPLM_API int XPLMSaveDataFile( + XPLMDataFileType inFileType, + const char * inFilePath); +#endif /* XPLM200 */ + +/*************************************************************************** + * X-PLANE MISC + ***************************************************************************/ + +/* + * XPLMHostApplicationID + * + * While the plug-in SDK is only accessible to plugins running inside X-Plane, + * the original authors considered extending the API to other applications + * that shared basic infrastructure with X-Plane. These enumerations are + * hold-overs from that original roadmap; all values other than X-Plane are + * deprecated. Your plugin should never need this enumeration. + * + */ +enum { + xplm_Host_Unknown = 0, + + xplm_Host_XPlane = 1, + +#if defined(XPLM_DEPRECATED) + xplm_Host_PlaneMaker = 2, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_WorldMaker = 3, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_Briefer = 4, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_PartMaker = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_YoungsMod = 6, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_XAuto = 7, + +#endif /* XPLM_DEPRECATED */ + +}; +typedef int XPLMHostApplicationID; + +/* + * XPLMLanguageCode + * + * These enums define what language the sim is running in. These enumerations + * do not imply that the sim can or does run in all of these languages; they + * simply provide a known encoding in the event that a given sim version is + * localized to a certain language. + * + */ +enum { + xplm_Language_Unknown = 0, + + xplm_Language_English = 1, + + xplm_Language_French = 2, + + xplm_Language_German = 3, + + xplm_Language_Italian = 4, + + xplm_Language_Spanish = 5, + + xplm_Language_Korean = 6, + +#if defined(XPLM200) + xplm_Language_Russian = 7, + +#endif /* XPLM200 */ +#if defined(XPLM200) + xplm_Language_Greek = 8, + +#endif /* XPLM200 */ +#if defined(XPLM200) + xplm_Language_Japanese = 9, + +#endif /* XPLM200 */ +#if defined(XPLM300) + xplm_Language_Chinese = 10, + +#endif /* XPLM300 */ + +}; +typedef int XPLMLanguageCode; + +#if defined(XPLM200) +/* + * XPLMError_f + * + * An XPLM error callback is a function that you provide to receive debugging + * information from the plugin SDK. See XPLMSetErrorCallback for more + * information. NOTE: for the sake of debugging, your error callback will be + * called even if your plugin is not enabled, allowing you to receive debug + * info in your XPluginStart and XPluginStop callbacks. To avoid causing logic + * errors in the management code, do not call any other plugin routines from + * your error callback - it is only meant for catching errors in the + * debugging. + * + */ +typedef void (* XPLMError_f)( + const char * inMessage); +#endif /* XPLM200 */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMInitialized + * + * Deprecated: This function returns 1 if X-Plane has properly initialized the + * plug-in system. If this routine returns 0, many XPLM functions will not + * work. + * + * NOTE: because plugins are always called from within the XPLM, there is no + * need to check for initialization; it will always return 1. This routine is + * deprecated - you do not need to check it before continuing within your + * plugin. + * + */ +XPLM_API int XPLMInitialized(void); +#endif /* XPLM_DEPRECATED */ + +/* + * XPLMGetVersions + * + * This routine returns the revision of both X-Plane and the XPLM DLL. All + * versions are three-digit decimal numbers (e.g. 606 for version 6.06 of + * X-Plane); the current revision of the XPLM is 200 (2.00). This routine also + * returns the host ID of the app running us. + * + * The most common use of this routine is to special-case around X-Plane + * version-specific behavior. + * + */ +XPLM_API void XPLMGetVersions( + int * outXPlaneVersion, + int * outXPLMVersion, + XPLMHostApplicationID * outHostID); + +/* + * XPLMGetLanguage + * + * This routine returns the langauge the sim is running in. + * + */ +XPLM_API XPLMLanguageCode XPLMGetLanguage(void); + +#if defined(XPLM200) +/* + * XPLMFindSymbol + * + * This routine will attempt to find the symbol passed in the inString + * parameter. If the symbol is found a pointer the function is returned, + * othewise the function will return NULL. + * + * You can use XPLMFindSymbol to utilize newer SDK API features without + * requiring newer versions of the SDK (and X-Plane) as your minimum X-Plane + * version as follows: + * + * * Define the XPLMnnn macro to the minimum required XPLM version you will + * ship with (e.g. XPLM210 for X-Plane 10 compatibility). + * + * * Use XPLMGetVersions and XPLMFindSymbol to detect that the host sim is + * new enough to use new functions and resolve function pointers. + * + * * Conditionally use the new functions if and only if XPLMFindSymbol only + * returns a non- NULL pointer. + * + * Warning: you should always check the XPLM API version as well as the + * results of XPLMFindSymbol to determine if funtionality is safe to use. + * + * To use functionality via XPLMFindSymbol you will need to copy your own + * definitions of the X-Plane API prototypes and cast the returned pointer to + * the correct type. + * + */ +XPLM_API void * XPLMFindSymbol( + const char * inString); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMSetErrorCallback + * + * XPLMSetErrorCallback installs an error-reporting callback for your plugin. + * Normally the plugin system performs minimum diagnostics to maximize + * performance. When you install an error callback, you will receive calls due + * to certain plugin errors, such as passing bad parameters or incorrect data. + * + * Important: the error callback determines *programming* errors, e.g. bad API + * parameters. Every error that is returned by the error callback represents a + * mistake in your plugin that you should fix. Error callbacks are not used to + * report expected run-time problems (e.g. disk I/O errors). + * + * The intention is for you to install the error callback during debug + * sections and put a break-point inside your callback. This will cause you to + * break into the debugger from within the SDK at the point in your plugin + * where you made an illegal call. + * + * Installing an error callback may activate error checking code that would + * not normally run, and this may adversely affect performance, so do not + * leave error callbacks installed in shipping plugins. Since the only useful + * response to an error is to change code, error callbacks are not useful "in + * the field". + * + */ +XPLM_API void XPLMSetErrorCallback( + XPLMError_f inCallback); +#endif /* XPLM200 */ + +/* + * XPLMDebugString + * + * This routine outputs a C-style string to the Log.txt file. The file is + * immediately flushed so you will not lose data. (This does cause a + * performance penalty.) + * + * Please do *not* leave routine diagnostic logging enabled in your shipping + * plugin. The X-Plane Log file is shared by X-Plane and every plugin in the + * system, and plugins that (when functioning normally) print verbose log + * output make it difficult for developers to find error conditions from other + * parts of the system. + * + */ +XPLM_API void XPLMDebugString( + const char * inString); + +/* + * XPLMSpeakString + * + * This function displays the string in a translucent overlay over the current + * display and also speaks the string if text-to-speech is enabled. The string + * is spoken asynchronously, this function returns immediately. This function + * may not speak or print depending on user preferences. + * + */ +XPLM_API void XPLMSpeakString( + const char * inString); + +/* + * XPLMGetVirtualKeyDescription + * + * Given a virtual key code (as defined in XPLMDefs.h) this routine returns a + * human-readable string describing the character. This routine is provided + * for showing users what keyboard mappings they have set up. The string may + * read 'unknown' or be a blank or NULL string if the virtual key is unknown. + * + */ +XPLM_API const char * XPLMGetVirtualKeyDescription( + char inVirtualKey); + +/* + * XPLMReloadScenery + * + * XPLMReloadScenery reloads the current set of scenery. You can use this + * function in two typical ways: simply call it to reload the scenery, picking + * up any new installed scenery, .env files, etc. from disk. Or, change the + * lat/ref and lon/ref data refs and then call this function to shift the + * scenery environment. This routine is equivalent to picking "reload + * scenery" from the developer menu. + * + */ +XPLM_API void XPLMReloadScenery(void); + +#if defined(XPLM200) +/*************************************************************************** + * X-PLANE COMMAND MANAGEMENT + ***************************************************************************/ +/* + * The command management APIs let plugins interact with the command-system in + * X-Plane, the abstraction behind keyboard presses and joystick buttons. This + * API lets you create new commands and modify the behavior (or get + * notification) of existing ones. + * + * X-Plane Command Phases + * ---------------------- + * + * X-Plane commands are not instantaneous; they operate over a duration. + * (Think of a joystick button press - you can press, hold down, and then + * release the joystick button; X-Plane commands model this entire process.) + * + * An X-Plane command consists of three phases: a beginning, continuous + * repetition, and an ending. The command may be repeated zero times in its + * duration, followed by one command ending. Command begin and end messges are + * balanced, but a command may be bound to more than one event source (e.g. a + * keyboard key and a joystick button), in which case you may receive a second + * begin during before any end). + * + * When you issue commands in the plugin system, you *must* balance every call + * to XPLMCommandBegin with a call to XPLMCommandEnd with the same command + * reference. + * + * Command Behavior Modification + * ----------------------------- + * + * You can register a callback to handle a command either before or after + * X-Plane does; if you receive the command before X-Plane you have the option + * to either let X-Plane handle the command or hide the command from X-Plane. + * This lets plugins both augment commands and replace them. + * + * If you register for an existing command, be sure that you are *consistent* + * in letting X-Plane handle or not handle the command; you are responsible + * for passing a *balanced* number of begin and end messages to X-Plane. (E.g. + * it is not legal to pass all the begin messages to X-Plane but hide all the + * end messages). + * + */ + + +/* + * XPLMCommandPhase + * + * The phases of a command. + * + */ +enum { + /* The command is being started. */ + xplm_CommandBegin = 0, + + /* The command is continuing to execute. */ + xplm_CommandContinue = 1, + + /* The command has ended. */ + xplm_CommandEnd = 2, + + +}; +typedef int XPLMCommandPhase; + +/* + * XPLMCommandRef + * + * A command ref is an opaque identifier for an X-Plane command. Command + * references stay the same for the life of your plugin but not between + * executions of X-Plane. Command refs are used to execute commands, create + * commands, and create callbacks for particular commands. + * + * Note that a command is not "owned" by a particular plugin. Since many + * plugins may participate in a command's execution, the command does not go + * away if the plugin that created it is unloaded. + * + */ +typedef void * XPLMCommandRef; + +/* + * XPLMCommandCallback_f + * + * A command callback is a function in your plugin that is called when a + * command is pressed. Your callback receives the command reference for the + * particular command, the phase of the command that is executing, and a + * reference pointer that you specify when registering the callback. + * + * Your command handler should return 1 to let processing of the command + * continue to other plugins and X-Plane, or 0 to halt processing, potentially + * bypassing X-Plane code. + * + */ +typedef int (* XPLMCommandCallback_f)( + XPLMCommandRef inCommand, + XPLMCommandPhase inPhase, + void * inRefcon); + +/* + * XPLMFindCommand + * + * XPLMFindCommand looks up a command by name, and returns its command + * reference or NULL if the command does not exist. + * + */ +XPLM_API XPLMCommandRef XPLMFindCommand( + const char * inName); + +/* + * XPLMCommandBegin + * + * XPLMCommandBegin starts the execution of a command, specified by its + * command reference. The command is "held down" until XPLMCommandEnd is + * called. You must balance each XPLMCommandBegin call with an XPLMCommandEnd + * call. + * + */ +XPLM_API void XPLMCommandBegin( + XPLMCommandRef inCommand); + +/* + * XPLMCommandEnd + * + * XPLMCommandEnd ends the execution of a given command that was started with + * XPLMCommandBegin. You must not issue XPLMCommandEnd for a command you did + * not begin. + * + */ +XPLM_API void XPLMCommandEnd( + XPLMCommandRef inCommand); + +/* + * XPLMCommandOnce + * + * This executes a given command momentarily, that is, the command begins and + * ends immediately. This is the equivalent of calling XPLMCommandBegin() and + * XPLMCommandEnd() back ot back. + * + */ +XPLM_API void XPLMCommandOnce( + XPLMCommandRef inCommand); + +/* + * XPLMCreateCommand + * + * XPLMCreateCommand creates a new command for a given string. If the command + * already exists, the existing command reference is returned. The description + * may appear in user interface contexts, such as the joystick configuration + * screen. + * + */ +XPLM_API XPLMCommandRef XPLMCreateCommand( + const char * inName, + const char * inDescription); + +/* + * XPLMRegisterCommandHandler + * + * XPLMRegisterCommandHandler registers a callback to be called when a command + * is executed. You provide a callback with a reference pointer. + * + * If inBefore is true, your command handler callback will be executed before + * X-Plane executes the command, and returning 0 from your callback will + * disable X-Plane's processing of the command. If inBefore is false, your + * callback will run after X-Plane. (You can register a single callback both + * before and after a command.) + * + */ +XPLM_API void XPLMRegisterCommandHandler( + XPLMCommandRef inComand, + XPLMCommandCallback_f inHandler, + int inBefore, + void * inRefcon); + +/* + * XPLMUnregisterCommandHandler + * + * XPLMUnregisterCommandHandler removes a command callback registered with + * XPLMRegisterCommandHandler. + * + */ +XPLM_API void XPLMUnregisterCommandHandler( + XPLMCommandRef inComand, + XPLMCommandCallback_f inHandler, + int inBefore, + void * inRefcon); + +#endif /* XPLM200 */ +#if defined(XPLM_DEPRECATED) +/*************************************************************************** + * X-PLANE USER INTERACTION + ***************************************************************************/ +/* + * WARNING: The legacy user interaction API is deprecated; while it was the + * only way to run commands in X-Plane 6,7 and 8, it is obsolete, and was + * replaced by the command system API in X-Plane 9. You should not use this + * API; replace any of the calls below with XPLMCommand invocations based on + * persistent command strings. The documentation that follows is for historic + * reference only. + * + * The legacy user interaction APIs let you simulate commands the user can do + * with a joystick, keyboard etc. Note that it is generally safer for future + * compatibility to use one of these commands than to manipulate the + * underlying sim data. + * + */ + + +/* + * XPLMCommandKeyID + * + * These enums represent all the keystrokes available within X-Plane. They can + * be sent to X-Plane directly. For example, you can reverse thrust using + * these enumerations. + * + */ +enum { + xplm_key_pause=0, + xplm_key_revthrust, + xplm_key_jettison, + xplm_key_brakesreg, + xplm_key_brakesmax, + xplm_key_gear, + xplm_key_timedn, + xplm_key_timeup, + xplm_key_fadec, + xplm_key_otto_dis, + xplm_key_otto_atr, + xplm_key_otto_asi, + xplm_key_otto_hdg, + xplm_key_otto_gps, + xplm_key_otto_lev, + xplm_key_otto_hnav, + xplm_key_otto_alt, + xplm_key_otto_vvi, + xplm_key_otto_vnav, + xplm_key_otto_nav1, + xplm_key_otto_nav2, + xplm_key_targ_dn, + xplm_key_targ_up, + xplm_key_hdgdn, + xplm_key_hdgup, + xplm_key_barodn, + xplm_key_baroup, + xplm_key_obs1dn, + xplm_key_obs1up, + xplm_key_obs2dn, + xplm_key_obs2up, + xplm_key_com1_1, + xplm_key_com1_2, + xplm_key_com1_3, + xplm_key_com1_4, + xplm_key_nav1_1, + xplm_key_nav1_2, + xplm_key_nav1_3, + xplm_key_nav1_4, + xplm_key_com2_1, + xplm_key_com2_2, + xplm_key_com2_3, + xplm_key_com2_4, + xplm_key_nav2_1, + xplm_key_nav2_2, + xplm_key_nav2_3, + xplm_key_nav2_4, + xplm_key_adf_1, + xplm_key_adf_2, + xplm_key_adf_3, + xplm_key_adf_4, + xplm_key_adf_5, + xplm_key_adf_6, + xplm_key_transpon_1, + xplm_key_transpon_2, + xplm_key_transpon_3, + xplm_key_transpon_4, + xplm_key_transpon_5, + xplm_key_transpon_6, + xplm_key_transpon_7, + xplm_key_transpon_8, + xplm_key_flapsup, + xplm_key_flapsdn, + xplm_key_cheatoff, + xplm_key_cheaton, + xplm_key_sbrkoff, + xplm_key_sbrkon, + xplm_key_ailtrimL, + xplm_key_ailtrimR, + xplm_key_rudtrimL, + xplm_key_rudtrimR, + xplm_key_elvtrimD, + xplm_key_elvtrimU, + xplm_key_forward, + xplm_key_down, + xplm_key_left, + xplm_key_right, + xplm_key_back, + xplm_key_tower, + xplm_key_runway, + xplm_key_chase, + xplm_key_free1, + xplm_key_free2, + xplm_key_spot, + xplm_key_fullscrn1, + xplm_key_fullscrn2, + xplm_key_tanspan, + xplm_key_smoke, + xplm_key_map, + xplm_key_zoomin, + xplm_key_zoomout, + xplm_key_cycledump, + xplm_key_replay, + xplm_key_tranID, + xplm_key_max +}; +typedef int XPLMCommandKeyID; + +/* + * XPLMCommandButtonID + * + * These are enumerations for all of the things you can do with a joystick + * button in X-Plane. They currently match the buttons menu in the equipment + * setup dialog, but these enums will be stable even if they change in + * X-Plane. + * + */ +enum { + xplm_joy_nothing=0, + xplm_joy_start_all, + xplm_joy_start_0, + xplm_joy_start_1, + xplm_joy_start_2, + xplm_joy_start_3, + xplm_joy_start_4, + xplm_joy_start_5, + xplm_joy_start_6, + xplm_joy_start_7, + xplm_joy_throt_up, + xplm_joy_throt_dn, + xplm_joy_prop_up, + xplm_joy_prop_dn, + xplm_joy_mixt_up, + xplm_joy_mixt_dn, + xplm_joy_carb_tog, + xplm_joy_carb_on, + xplm_joy_carb_off, + xplm_joy_trev, + xplm_joy_trm_up, + xplm_joy_trm_dn, + xplm_joy_rot_trm_up, + xplm_joy_rot_trm_dn, + xplm_joy_rud_lft, + xplm_joy_rud_cntr, + xplm_joy_rud_rgt, + xplm_joy_ail_lft, + xplm_joy_ail_cntr, + xplm_joy_ail_rgt, + xplm_joy_B_rud_lft, + xplm_joy_B_rud_rgt, + xplm_joy_look_up, + xplm_joy_look_dn, + xplm_joy_look_lft, + xplm_joy_look_rgt, + xplm_joy_glance_l, + xplm_joy_glance_r, + xplm_joy_v_fnh, + xplm_joy_v_fwh, + xplm_joy_v_tra, + xplm_joy_v_twr, + xplm_joy_v_run, + xplm_joy_v_cha, + xplm_joy_v_fr1, + xplm_joy_v_fr2, + xplm_joy_v_spo, + xplm_joy_flapsup, + xplm_joy_flapsdn, + xplm_joy_vctswpfwd, + xplm_joy_vctswpaft, + xplm_joy_gear_tog, + xplm_joy_gear_up, + xplm_joy_gear_down, + xplm_joy_lft_brake, + xplm_joy_rgt_brake, + xplm_joy_brakesREG, + xplm_joy_brakesMAX, + xplm_joy_speedbrake, + xplm_joy_ott_dis, + xplm_joy_ott_atr, + xplm_joy_ott_asi, + xplm_joy_ott_hdg, + xplm_joy_ott_alt, + xplm_joy_ott_vvi, + xplm_joy_tim_start, + xplm_joy_tim_reset, + xplm_joy_ecam_up, + xplm_joy_ecam_dn, + xplm_joy_fadec, + xplm_joy_yaw_damp, + xplm_joy_art_stab, + xplm_joy_chute, + xplm_joy_JATO, + xplm_joy_arrest, + xplm_joy_jettison, + xplm_joy_fuel_dump, + xplm_joy_puffsmoke, + xplm_joy_prerotate, + xplm_joy_UL_prerot, + xplm_joy_UL_collec, + xplm_joy_TOGA, + xplm_joy_shutdown, + xplm_joy_con_atc, + xplm_joy_fail_now, + xplm_joy_pause, + xplm_joy_rock_up, + xplm_joy_rock_dn, + xplm_joy_rock_lft, + xplm_joy_rock_rgt, + xplm_joy_rock_for, + xplm_joy_rock_aft, + xplm_joy_idle_hilo, + xplm_joy_lanlights, + xplm_joy_max +}; +typedef int XPLMCommandButtonID; + +/* + * XPLMSimulateKeyPress + * + * This function simulates a key being pressed for X-Plane. The keystroke goes + * directly to X-Plane; it is never sent to any plug-ins. However, since this + * is a raw key stroke it may be mapped by the keys file or enter text into a + * field. + * + * Deprecated: use XPLMCommandOnce + * + */ +XPLM_API void XPLMSimulateKeyPress( + int inKeyType, + int inKey); + +/* + * XPLMCommandKeyStroke + * + * This routine simulates a command-key stroke. However, the keys are done by + * function, not by actual letter, so this function works even if the user has + * remapped their keyboard. Examples of things you might do with this include + * pausing the simulator. + * + * Deprecated: use XPLMCommandOnce + * + */ +XPLM_API void XPLMCommandKeyStroke( + XPLMCommandKeyID inKey); + +/* + * XPLMCommandButtonPress + * + * This function simulates any of the actions that might be taken by pressing + * a joystick button. However, this lets you call the command directly rather + * than have to know which button is mapped where. Important: you must release + * each button you press. The APIs are separate so that you can 'hold down' a + * button for a fixed amount of time. + * + * Deprecated: use XPLMCommandBegin. + * + */ +XPLM_API void XPLMCommandButtonPress( + XPLMCommandButtonID inButton); + +/* + * XPLMCommandButtonRelease + * + * This function simulates any of the actions that might be taken by pressing + * a joystick button. See XPLMCommandButtonPress. + * + * Deprecated: use XPLMCommandEnd. + * + */ +XPLM_API void XPLMCommandButtonRelease( + XPLMCommandButtonID inButton); + +#endif /* XPLM_DEPRECATED */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPStandardWidgets.pas b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPStandardWidgets.pas new file mode 100644 index 0000000..d77f383 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPStandardWidgets.pas @@ -0,0 +1,470 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPStandardWidgets; +INTERFACE +{ + ## THEORY OF OPERATION + + The standard widgets are widgets built into the widgets library. While you + can gain access to the widget function that drives them, you generally use + them by calling XPCreateWidget and then listening for special messages, + etc. + + The standard widgets often send mesages to themselves when the user + performs an event; these messages are sent up the widget hierarchy until + they are handled. So you can add a widget proc directly to a push button + (for example) to intercept the message when it is clicked, or you can put + one widget proc on a window for all of the push buttons in the window. Most + of these messages contain the original widget ID as a parameter so you can + know which widget is messaging no matter who it is sent to. +} + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * MAIN WINDOW + ___________________________________________________________________________} +{ + The main window widget class provides a "window" as the user knows it. + These windows are dragable and can be selected. Use them to create floating + windows and non-modal dialogs. +} + + +CONST + xpWidgetClass_MainWindow = 1; + + { + Main Window Type Values + + These type values are used to control the appearance of a main window. + } + { The standard main window; pin stripes on XP7, metal frame on XP 6. } + xpMainWindowStyle_MainWindow = 0 +; + { A translucent dark gray window, like the one ATC messages appear in. } + xpMainWindowStyle_Translucent = 1 +; + + { + Main Window Properties + } + { This property specifies the type of window. Set to one of the main window } + { types above. } + xpProperty_MainWindowType = 1100 +; + { This property specifies whether the main window has close boxes in its } + { corners. } + xpProperty_MainWindowHasCloseBoxes = 1200 +; + + { + MainWindow Messages + } + { This message is sent when the close buttons are pressed for your window. } + xpMessage_CloseButtonPushed = 1200 +; + +{___________________________________________________________________________ + * SUB WINDOW + ___________________________________________________________________________} +{ + X-Plane dialogs are divided into separate areas; the sub window widgets + allow you to make these areas. Create one main window and place several + subwindows inside it. Then place your controls inside the subwindows. +} + + +CONST + xpWidgetClass_SubWindow = 2; + + { + SubWindow Type Values + + These values control the appearance of the subwindow. + } + { A panel that sits inside a main window. } + xpSubWindowStyle_SubWindow = 0 +; + { A screen that sits inside a panel for showing text information. } + xpSubWindowStyle_Screen = 2 +; + { A list view for scrolling lists. } + xpSubWindowStyle_ListView = 3 +; + + { + SubWindow Properties + } + { This property specifies the type of window. Set to one of the subwindow } + { types above. } + xpProperty_SubWindowType = 1200 +; + +{___________________________________________________________________________ + * BUTTON + ___________________________________________________________________________} +{ + The button class provides a number of different button styles and + behaviors, including push buttons, radio buttons, check boxes, etc. The + button label appears on or next to the button depending on the button's + appearance, or type. + + The button's behavior is a separate property that dictates who it hilights + and what kinds of messages it sends. Since behavior and type are different, + you can do strange things like make check boxes that act as push buttons or + push buttons with radio button behavior. + + In X-Plane 6 there were no check box graphics. The result is the following + behavior: in X-Plane + 6 all check box and radio buttons are round (radio-button style) buttons; + in X-Plane 7 they are all square (check-box style) buttons. In a future + version of X-Plane, the xpButtonBehavior enums will provide the correct + graphic (check box or radio button) giving the expected result. +} + + +CONST + xpWidgetClass_Button = 3; + + { + Button Types + + These define the visual appearance of buttons but not how they respond to + the mouse. + } + { This is a standard push button, like an 'OK' or 'Cancel' button in a dialog} + { box. } + xpPushButton = 0 +; + { A check box or radio button. Use this and the button behaviors below to } + { get the desired behavior. } + xpRadioButton = 1 +; + { A window close box. } + xpWindowCloseBox = 3 +; + { A small down arrow. } + xpLittleDownArrow = 5 +; + { A small up arrow. } + xpLittleUpArrow = 6 +; + + { + Button Behavior Values + + These define how the button responds to mouse clicks. + } + { Standard push button behavior. The button hilites while the mouse is } + { clicked over it and unhilites when the mouse is moved outside of it or } + { released. If the mouse is released over the button, the } + { xpMsg_PushButtonPressed message is sent. } + xpButtonBehaviorPushButton = 0 +; + { Check box behavior. The button immediately toggles its value when the mouse} + { is clicked and sends out a xpMsg_ButtonStateChanged message. } + xpButtonBehaviorCheckBox = 1 +; + { Radio button behavior. The button immediately sets its state to one and } + { sends out a xpMsg_ButtonStateChanged message if it was not already set to } + { one. You must turn off other radio buttons in a group in your code. } + xpButtonBehaviorRadioButton = 2 +; + + { + Button Properties + } + { This property sets the visual type of button. Use one of the button types } + { above. } + xpProperty_ButtonType = 1300 +; + { This property sets the button's behavior. Use one of the button behaviors } + { above. } + xpProperty_ButtonBehavior = 1301 +; + { This property tells whether a check box or radio button is "checked" or } + { not. Not used for push buttons. } + xpProperty_ButtonState = 1302 +; + + { + Button Messages + + These messages are sent by the button to itself and then up the widget + chain when the button is clicked. (You may intercept them by providing a + widget handler for the button itself or by providing a handler in a parent + widget.) + } + { This message is sent when the user completes a click and release in a } + { button with push button behavior. Parameter one of the message is the } + { widget ID of the button. This message is dispatched up the widget } + { hierarchy. } + xpMsg_PushButtonPressed = 1300 +; + { This message is sent when a button is clicked that has radio button or } + { check box behavior and its value changes. (Note that if the value changes } + { by setting a property you do not receive this message!) Parameter one is } + { the widget ID of the button, parameter 2 is the new state value, either } + { zero or one. This message is dispatched up the widget hierarchy. } + xpMsg_ButtonStateChanged = 1301 +; + +{___________________________________________________________________________ + * TEXT FIELD + ___________________________________________________________________________} +{ + The text field widget provides an editable text field including mouse + selection and keyboard navigation. The contents of the text field are its + descriptor. (The descriptor changes as the user types.) + + The text field can have a number of types, that effect the visual layout of + the text field. The text field sends messages to itself so you may control + its behavior. + + If you need to filter keystrokes, add a new handler and intercept the key + press message. Since key presses are passed by pointer, you can modify the + keystroke and pass it through to the text field widget. + + WARNING: in X-Plane before 7.10 (including 6.70) null characters could + crash X-Plane. To prevent this, wrap this object with a filter function + (more instructions can be found on the SDK website). +} + + +CONST + xpWidgetClass_TextField = 4; + + { + Text Field Type Values + + These control the look of the text field. + } + { A field for text entry. } + xpTextEntryField = 0 +; + { A transparent text field. The user can type and the text is drawn, but no } + { background is drawn. You can draw your own background by adding a widget } + { handler and prehandling the draw message. } + xpTextTransparent = 3 +; + { A translucent edit field, dark gray. } + xpTextTranslucent = 4 +; + + { + Text Field Properties + } + { This is the character position the selection starts at, zero based. If it } + { is the same as the end insertion point, the insertion point is not a } + { selection. } + xpProperty_EditFieldSelStart = 1400 +; + { This is the character position of the end of the selection. } + xpProperty_EditFieldSelEnd = 1401 +; + { This is the character position a drag was started at if the user is } + { dragging to select text, or -1 if a drag is not in progress. } + xpProperty_EditFieldSelDragStart = 1402 +; + { This is the type of text field to display, from the above list. } + xpProperty_TextFieldType = 1403 +; + { Set this property to 1 to password protect the field. Characters will be } + { drawn as *s even though the descriptor will contain plain-text. } + xpProperty_PasswordMode = 1404 +; + { The max number of characters you can enter, if limited. Zero means } + { unlimited. } + xpProperty_MaxCharacters = 1405 +; + { The first visible character on the left. This effectively scrolls the text} + { field. } + xpProperty_ScrollPosition = 1406 +; + { The font to draw the field's text with. (An XPLMFontID.) } + xpProperty_Font = 1407 +; + { This is the active side of the insert selection. (Internal) } + xpProperty_ActiveEditSide = 1408 +; + + { + Text Field Messages + } + { The text field sends this message to itself when its text changes. It sends} + { the message up the call chain; param1 is the text field's widget ID. } + xpMsg_TextFieldChanged = 1400 +; + +{___________________________________________________________________________ + * SCROLL BAR + ___________________________________________________________________________} +{ + A standard scroll bar or slider control. The scroll bar has a minimum, + maximum and current value that is updated when the user drags it. The + scroll bar sends continuous messages as it is dragged. +} + + +CONST + xpWidgetClass_ScrollBar = 5; + + { + Scroll Bar Type Values + + This defines how the scroll bar looks. + } + { A standard X-Plane scroll bar (with arrows on the ends). } + xpScrollBarTypeScrollBar = 0 +; + { A slider, no arrows. } + xpScrollBarTypeSlider = 1 +; + + { + Scroll Bar Properties + } + { The current position of the thumb (in between the min and max, inclusive) } + xpProperty_ScrollBarSliderPosition = 1500 +; + { The value the scroll bar has when the thumb is in the lowest position. } + xpProperty_ScrollBarMin = 1501 +; + { The value the scroll bar has when the thumb is in the highest position. } + xpProperty_ScrollBarMax = 1502 +; + { How many units to move the scroll bar when clicking next to the thumb. The } + { scroll bar always moves one unit when the arrows are clicked. } + xpProperty_ScrollBarPageAmount = 1503 +; + { The type of scrollbar from the enums above. } + xpProperty_ScrollBarType = 1504 +; + { Used internally. } + xpProperty_ScrollBarSlop = 1505 +; + + { + Scroll Bar Messages + } + { The scroll bar sends this message when the slider position changes. It } + { sends the message up the call chain; param1 is the Scroll Bar widget ID. } + xpMsg_ScrollBarSliderPositionChanged = 1500 +; + +{___________________________________________________________________________ + * CAPTION + ___________________________________________________________________________} +{ + A caption is a simple widget that shows its descriptor as a string, useful + for labeling parts of a window. It always shows its descriptor as its + string and is otherwise transparent. +} + + +CONST + xpWidgetClass_Caption = 6; + + { + Caption Properties + } + { This property specifies whether the caption is lit; use lit captions } + { against screens. } + xpProperty_CaptionLit = 1600 +; + +{___________________________________________________________________________ + * GENERAL GRAPHICS + ___________________________________________________________________________} +{ + The general graphics widget can show one of many icons available from + X-Plane. +} + + +CONST + xpWidgetClass_GeneralGraphics = 7; + + { + General Graphics Types Values + + These define the icon for the general graphics. + } + xpShip = 4 +; + xpILSGlideScope = 5 +; + xpMarkerLeft = 6 +; + xp_Airport = 7 +; + xpNDB = 8 +; + xpVOR = 9 +; + xpRadioTower = 10 +; + xpAircraftCarrier = 11 +; + xpFire = 12 +; + xpMarkerRight = 13 +; + xpCustomObject = 14 +; + xpCoolingTower = 15 +; + xpSmokeStack = 16 +; + xpBuilding = 17 +; + xpPowerLine = 18 +; + xpVORWithCompassRose = 19 +; + xpOilPlatform = 21 +; + xpOilPlatformSmall = 22 +; + xpWayPoint = 23 +; + + { + General Graphics Properties + } + { This property controls the type of icon that is drawn. } + xpProperty_GeneralGraphicsType = 1700 +; + +{___________________________________________________________________________ + * PROGRESS INDICATOR + ___________________________________________________________________________} +{ + This widget implements a progress indicator as seen when X-Plane starts up. +} + +CONST + xpWidgetClass_Progress = 8; + + { + Progress Indicator Properties + } + { This is the current value of the progress indicator. } + xpProperty_ProgressPosition = 1800 +; + { This is the minimum value, equivalent to 0% filled. } + xpProperty_ProgressMin = 1801 +; + { This is the maximum value, equivalent to 100% filled. } + xpProperty_ProgressMax = 1802 +; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPUIGraphics.pas b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPUIGraphics.pas new file mode 100644 index 0000000..65e0636 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPUIGraphics.pas @@ -0,0 +1,342 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPUIGraphics; +INTERFACE + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * UI GRAPHICS + ___________________________________________________________________________} + + { + XPWindowStyle + + There are a few built-in window styles in X-Plane that you can use. + + Note that X-Plane 6 does not offer real shadow-compositing; you must make + sure to put a window on top of another window of the right style to the + shadows work, etc. This applies to elements with insets and shadows. The + rules are: + + Sub windows must go on top of main windows, and screens and list views on + top of subwindows. Only help and main windows can be over the main screen. + + With X-Plane 7 any window or element may be placed over any other element. + + Some windows are scaled by stretching, some by repeating. The drawing + routines know which scaling method to use. The list view cannot be rescaled + in X-Plane 6 because it has both a repeating pattern and a gradient in one + element. All other elements can be rescaled. + } +TYPE + XPWindowStyle = ( + { An LCD screen that shows help. } + xpWindow_Help = 0 + + { A dialog box window. } + ,xpWindow_MainWindow = 1 + + { A panel or frame within a dialog box window. } + ,xpWindow_SubWindow = 2 + + { An LCD screen within a panel to hold text displays. } + ,xpWindow_Screen = 4 + + { A list view within a panel for scrolling file names, etc. } + ,xpWindow_ListView = 5 + + ); + PXPWindowStyle = ^XPWindowStyle; + + { + XPDrawWindow + + This routine draws a window of the given dimensions at the given offset on + the virtual screen in a given style. The window is automatically scaled as + appropriate using a bitmap scaling technique (scaling or repeating) as + appropriate to the style. + } + PROCEDURE XPDrawWindow( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inStyle : XPWindowStyle); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWindowDefaultDimensions + + This routine returns the default dimensions for a window. Output is either + a minimum or fixed value depending on whether the window is scalable. + } + PROCEDURE XPGetWindowDefaultDimensions( + inStyle : XPWindowStyle; + outWidth : PInteger; { Can be nil } + outHeight : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPElementStyle + + Elements are individually drawable UI things like push buttons, etc. The + style defines what kind of element you are drawing. Elements can be + stretched in one or two dimensions (depending on the element). Some + elements can be lit. + + In X-Plane 6 some elements must be drawn over metal. Some are scalable and + some are not. Any element can be drawn anywhere in X-Plane 7. + + Scalable Axis Required Background + } +TYPE + XPElementStyle = ( + { x metal } + xpElement_TextField = 6 + + { none metal } + ,xpElement_CheckBox = 9 + + { none metal } + ,xpElement_CheckBoxLit = 10 + + { none window header } + ,xpElement_WindowCloseBox = 14 + + { none window header } + ,xpElement_WindowCloseBoxPressed = 15 + + { x metal } + ,xpElement_PushButton = 16 + + { x metal } + ,xpElement_PushButtonLit = 17 + + { none any } + ,xpElement_OilPlatform = 24 + + { none any } + ,xpElement_OilPlatformSmall = 25 + + { none any } + ,xpElement_Ship = 26 + + { none any } + ,xpElement_ILSGlideScope = 27 + + { none any } + ,xpElement_MarkerLeft = 28 + + { none any } + ,xpElement_Airport = 29 + + { none any } + ,xpElement_Waypoint = 30 + + { none any } + ,xpElement_NDB = 31 + + { none any } + ,xpElement_VOR = 32 + + { none any } + ,xpElement_RadioTower = 33 + + { none any } + ,xpElement_AircraftCarrier = 34 + + { none any } + ,xpElement_Fire = 35 + + { none any } + ,xpElement_MarkerRight = 36 + + { none any } + ,xpElement_CustomObject = 37 + + { none any } + ,xpElement_CoolingTower = 38 + + { none any } + ,xpElement_SmokeStack = 39 + + { none any } + ,xpElement_Building = 40 + + { none any } + ,xpElement_PowerLine = 41 + + { none metal } + ,xpElement_CopyButtons = 45 + + { none metal } + ,xpElement_CopyButtonsWithEditingGrid = 46 + + { x, y metal } + ,xpElement_EditingGrid = 47 + + { THIS CAN PROBABLY BE REMOVED } + ,xpElement_ScrollBar = 48 + + { none any } + ,xpElement_VORWithCompassRose = 49 + + { none metal } + ,xpElement_Zoomer = 51 + + { x, y metal } + ,xpElement_TextFieldMiddle = 52 + + { none metal } + ,xpElement_LittleDownArrow = 53 + + { none metal } + ,xpElement_LittleUpArrow = 54 + + { none metal } + ,xpElement_WindowDragBar = 61 + + { none metal } + ,xpElement_WindowDragBarSmooth = 62 + + ); + PXPElementStyle = ^XPElementStyle; + + { + XPDrawElement + + XPDrawElement draws a given element at an offset on the virtual screen in + set dimensions. + *Even* if the element is not scalable, it will be scaled if the width and + height do not match the preferred dimensions; it'll just look ugly. Pass + inLit to see the lit version of the element; if the element cannot be lit + this is ignored. + } + PROCEDURE XPDrawElement( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inStyle : XPElementStyle; + inLit : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetElementDefaultDimensions + + This routine returns the recommended or minimum dimensions of a given UI + element. outCanBeLit tells whether the element has both a lit and unlit + state. Pass `NULL` to not receive any of these parameters. + } + PROCEDURE XPGetElementDefaultDimensions( + inStyle : XPElementStyle; + outWidth : PInteger; { Can be nil } + outHeight : PInteger; { Can be nil } + outCanBeLit : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPTrackStyle + + A track is a UI element that displays a value vertically or horizontally. + X-Plane has three kinds of tracks: scroll bars, sliders, and progress bars. + Tracks can be displayed either horizontally or vertically; tracks will + choose their own layout based on the larger dimension of their dimensions + (e.g. they know if they are tall or wide). Sliders may be lit or unlit + (showing the user manipulating them). + + - ScrollBar: this is a standard scroll bar with arrows and a thumb to drag. + - Slider: this is a simple track with a ball in the middle that can be + slid. + - Progress: this is a progress indicator showing how a long task is going. + } +TYPE + XPTrackStyle = ( + { not over metal can be lit can be rotated } + xpTrack_ScrollBar = 0 + + { over metal can be lit can be rotated } + ,xpTrack_Slider = 1 + + { over metal cannot be lit cannot be rotated } + ,xpTrack_Progress = 2 + + ); + PXPTrackStyle = ^XPTrackStyle; + + { + XPDrawTrack + + This routine draws a track. You pass in the track dimensions and size; the + track picks the optimal orientation for these dimensions. Pass in the + track's minimum current and maximum values; the indicator will be + positioned appropriately. You can also specify whether the track is lit or + not. + } + PROCEDURE XPDrawTrack( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inMin : Integer; + inMax : Integer; + inValue : Integer; + inTrackStyle : XPTrackStyle; + inLit : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetTrackDefaultDimensions + + This routine returns a track's default smaller dimension; all tracks are + scalable in the larger dimension. It also returns whether a track can be + lit. + } + PROCEDURE XPGetTrackDefaultDimensions( + inStyle : XPTrackStyle; + outWidth : PInteger; + outCanBeLit : PInteger); + cdecl; external XPWIDGETS.DLL; + + { + XPGetTrackMetrics + + This routine returns the metrics of a track. If you want to write UI code + to manipulate a track, this routine helps you know where the mouse + locations are. For most other elements, the rectangle the element is drawn + in is enough information. However, the scrollbar drawing routine does some + automatic placement; this routine lets you know where things ended up. You + pass almost everything you would pass to the draw routine. You get out the + orientation, and other useful stuff. + + Besides orientation, you get five dimensions for the five parts of a + scrollbar, which are the down button, down area (area before the thumb), + the thumb, and the up area and button. For horizontal scrollers, the left + button decreases; for vertical scrollers, the top button decreases. + } + PROCEDURE XPGetTrackMetrics( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inMin : Integer; + inMax : Integer; + inValue : Integer; + inTrackStyle : XPTrackStyle; + outIsVertical : PInteger; + outDownBtnSize : PInteger; + outDownPageSize : PInteger; + outThumbSize : PInteger; + outUpPageSize : PInteger; + outUpBtnSize : PInteger); + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgetDefs.pas b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgetDefs.pas new file mode 100644 index 0000000..1cc342f --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgetDefs.pas @@ -0,0 +1,427 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgetDefs; +INTERFACE + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * WIDGET DEFINITIONS + ___________________________________________________________________________} +{ + A widget is a call-back driven screen entity like a push-button, window, + text entry field, etc. + + Use the widget API to create widgets of various classes. You can nest them + into trees of widgets to create complex user interfaces. +} + + +TYPE + { + XPWidgetID + + A Widget ID is an opaque unique non-zero handle identifying your widget. + Use 0 to specify "no widget". This type is defined as wide enough to hold a + pointer. You receive a widget ID when you create a new widget and then use + that widget ID to further refer to the widget. + } + XPWidgetID = pointer; + PXPWidgetID = ^XPWidgetID; + + { + XPWidgetPropertyID + + Properties are values attached to instances of your widgets. A property is + identified by a 32-bit ID and its value is the width of a pointer. + + Each widget instance may have a property or not have it. When you set a + property on a widget for the first time, the property is added to the + widget; it then stays there for the life of the widget. + + Some property IDs are predefined by the widget package; you can make up + your own property IDs as well. + } + XPWidgetPropertyID = ( + { A window's refcon is an opaque value used by client code to find other data} + { based on it. } + xpProperty_Refcon = 0 + + { These properties are used by the utlities to implement dragging. } + ,xpProperty_Dragging = 1 + + ,xpProperty_DragXOff = 2 + + ,xpProperty_DragYOff = 3 + + { Is the widget hilited? (For widgets that support this kind of thing.) } + ,xpProperty_Hilited = 4 + + { Is there a C++ object attached to this widget? } + ,xpProperty_Object = 5 + + { If this property is 1, the widget package will use OpenGL to restrict } + { drawing to the Wiget's exposed rectangle. } + ,xpProperty_Clip = 6 + + { Is this widget enabled (for those that have a disabled state too)? } + ,xpProperty_Enabled = 7 + + { NOTE: Property IDs 1 - 999 are reserved for the widgets library. } + { } + { NOTE: Property IDs 1000 - 9999 are allocated to the standard widget classes} + { provided with the library. } + { } + { Properties 1000 - 1099 are for widget class 0, 1100 - 1199 for widget class} + { 1, etc. } + ,xpProperty_UserStart = 10000 + + ); + PXPWidgetPropertyID = ^XPWidgetPropertyID; + + { + XPMouseState_t + + When the mouse is clicked or dragged, a pointer to this structure is passed + to your widget function. + } + XPMouseState_t = RECORD + x : Integer; + y : Integer; + { Mouse Button number, left = 0 (right button not yet supported. } + button : Integer; +{$IFDEF XPLM200} + { Scroll wheel delta (button in this case would be the wheel axis number). } + delta : Integer; +{$ENDIF XPLM200} + END; + PXPMouseState_t = ^XPMouseState_t; + + { + XPKeyState_t + + When a key is pressed, a pointer to this struct is passed to your widget + function. + } + XPKeyState_t = RECORD + { The ASCII key that was pressed. WARNING: this may be 0 for some non-ASCII } + { key sequences. } + key : XPLMChar; + { The flags. Make sure to check this if you only want key-downs! } + flags : XPLMKeyFlags; + { The virtual key code for the key } + vkey : XPLMChar; + END; + PXPKeyState_t = ^XPKeyState_t; + + { + XPWidgetGeometryChange_t + + This structure contains the deltas for your widget's geometry when it + changes. + } + XPWidgetGeometryChange_t = RECORD + dx : Integer; + { +Y = the widget moved up } + dy : Integer; + dwidth : Integer; + dheight : Integer; + END; + PXPWidgetGeometryChange_t = ^XPWidgetGeometryChange_t; + + { + XPDispatchMode + + The dispatching modes describe how the widgets library sends out messages. + Currently there are three modes: + } + XPDispatchMode = ( + { The message will only be sent to the target widget. } + xpMode_Direct = 0 + + { The message is sent to the target widget, then up the chain of parents } + { until the message is handled or a parentless widget is reached. } + ,xpMode_UpChain = 1 + + { The message is sent to the target widget and then all of its children } + { recursively depth-first. } + ,xpMode_Recursive = 2 + + { The message is snet just to the target, but goes to every callback, even if} + { it is handled. } + ,xpMode_DirectAllCallbacks = 3 + + { The message is only sent to the very first handler even if it is not } + { accepted. (This is really only useful for some internal widget library } + { functions.) } + ,xpMode_Once = 4 + + ); + PXPDispatchMode = ^XPDispatchMode; + + { + XPWidgetClass + + Widget classes define predefined widget types. A widget class basically + specifies from a library the widget function to be used for the widget. + Most widgets can be made right from classes. + } + XPWidgetClass = Integer; + PXPWidgetClass = ^XPWidgetClass; + +CONST + { An unspecified widget class. Other widget classes are in } + { XPStandardWidgets.h } + xpWidgetClass_None = 0; + +{___________________________________________________________________________ + * WIDGET MESSAGES + ___________________________________________________________________________} + + { + XPWidgetMessage + + Widgets receive 32-bit messages indicating what action is to be taken or + notifications of events. The list of messages may be expanded. + } +TYPE + XPWidgetMessage = ( + { No message, should not be sent. } + xpMsg_None = 0 + + { The create message is sent once per widget that is created with your widget} + { function and once for any widget that has your widget function attached. } + { } + { Dispatching: Direct } + { } + { Param 1: 1 if you are being added as a subclass, 0 if the widget is first } + { being created. } + ,xpMsg_Create = 1 + + { The destroy message is sent once for each message that is destroyed that } + { has your widget function. } + { } + { Dispatching: Direct for all } + { } + { Param 1: 1 if being deleted by a recursive delete to the parent, 0 for } + { explicit deletion. } + ,xpMsg_Destroy = 2 + + { The paint message is sent to your widget to draw itself. The paint message } + { is the bare-bones message; in response you must draw yourself, draw your } + { children, set up clipping and culling, check for visibility, etc. If you } + { don't want to do all of this, ignore the paint message and a draw message } + { (see below) will be sent to you. } + { } + { Dispatching: Direct } + ,xpMsg_Paint = 3 + + { The draw message is sent to your widget when it is time to draw yourself. } + { OpenGL will be set up to draw in 2-d global screen coordinates, but you } + { should use the XPLM to set up OpenGL state. } + { } + { Dispatching: Direct } + ,xpMsg_Draw = 4 + + { The key press message is sent once per key that is pressed. The first } + { parameter is the type of key code (integer or char) and the second is the } + { code itself. By handling this event, you consume the key stroke. } + { } + { Handling this message 'consumes' the keystroke; not handling it passes it } + { to your parent widget. } + { } + { Dispatching: Up Chain } + { } + { Param 1: A pointer to an XPKeyState_t structure with the keystroke. } + ,xpMsg_KeyPress = 5 + + { Keyboard focus is being given to you. By handling this message you accept } + { keyboard focus. The first parameter will be one if a child of yours gave up} + { focus to you, 0 if someone set focus on you explicitly. } + { } + { Handling this message accepts focus; not handling refuses focus. } + { } + { Dispatching: direct } + { } + { Param 1: 1 if you are gaining focus because your child is giving it up, 0 } + { if someone is explicitly giving you focus. } + ,xpMsg_KeyTakeFocus = 6 + + { Keyboard focus is being taken away from you. The first parameter will be } + { one if you are losing focus because another widget is taking it, or 0 if } + { someone called the API to make you lose focus explicitly. } + { } + { Dispatching: Direct } + { } + { Param 1: 1 if focus is being taken by another widget, 0 if code requested } + { to remove focus. } + ,xpMsg_KeyLoseFocus = 7 + + { You receive one mousedown event per click with a mouse-state structure } + { pointed to by parameter 1, by accepting this you eat the click, otherwise } + { your parent gets it. You will not receive drag and mouse up messages if you} + { do not accept the down message. } + { } + { Handling this message consumes the mouse click, not handling it passes it } + { to the next widget. You can act 'transparent' as a window by never handling} + { moues clicks to certain areas. } + { } + { Dispatching: Up chain NOTE: Technically this is direct dispatched, but the } + { widgets library will shop it to each widget until one consumes the click, } + { making it effectively "up chain". } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseDown = 8 + + { You receive a series of mouse drag messages (typically one per frame in the} + { sim) as the mouse is moved once you have accepted a mouse down message. } + { Parameter one points to a mouse-state structure describing the mouse } + { location. You will continue to receive these until the mouse button is } + { released. You may receive multiple mouse state messages with the same mouse} + { position. You will receive mouse drag events even if the mouse is dragged } + { out of your current or original bounds at the time of the mouse down. } + { } + { Dispatching: Direct } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseDrag = 9 + + { The mouseup event is sent once when the mouse button is released after a } + { drag or click. You only receive this message if you accept the mouseDown } + { message. Parameter one points to a mouse state structure. } + { } + { Dispatching: Direct } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseUp = 10 + + { Your geometry or a child's geometry is being changed. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the original reshaped target. } + { } + { Param 2: A pointer to a XPWidgetGeometryChange_t struct describing the } + { change. } + ,xpMsg_Reshape = 11 + + { Your exposed area has changed. } + { } + { Dispatching: Direct } + ,xpMsg_ExposedChanged = 12 + + { A child has been added to you. The child's ID is passed in parameter one. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of the child being added. } + ,xpMsg_AcceptChild = 13 + + { A child has been removed from to you. The child's ID is passed in parameter} + { one. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of the child being removed. } + ,xpMsg_LoseChild = 14 + + { You now have a new parent, or have no parent. The parent's ID is passed in,} + { or 0 for no parent. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of your parent } + ,xpMsg_AcceptParent = 15 + + { You or a child has been shown. Note that this does not include you being } + { shown because your parent was shown, you were put in a new parent, your } + { root was shown, etc. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the shown widget. } + ,xpMsg_Shown = 16 + + { You have been hidden. See limitations above. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the hidden widget. } + ,xpMsg_Hidden = 17 + + { Your descriptor has changed. } + { } + { Dispatching: Direct } + ,xpMsg_DescriptorChanged = 18 + + { A property has changed. Param 1 contains the property ID. } + { } + { Dispatching: Direct } + { } + { Param 1: The Property ID being changed. } + { } + { Param 2: The new property value } + ,xpMsg_PropertyChanged = 19 + +{$IFDEF XPLM200} + { The mouse wheel has moved. } + { } + { Return 1 to consume the mouse wheel move, or 0 to pass the message to a } + { parent. Dispatching: Up chain } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseWheel = 20 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { The cursor is over your widget. If you consume this message, change the } + { XPLMCursorStatus value to indicate the desired result, with the same rules } + { as in XPLMDisplay.h. } + { } + { Return 1 to consume this message, 0 to pass it on. } + { } + { Dispatching: Up chain Param 1: A pointer to an XPMouseState_t struct } + { containing the mouse status. } + { } + { Param 2: A pointer to a XPLMCursorStatus - set this to the cursor result } + { you desire. } + ,xpMsg_CursorAdjust = 21 +{$ENDIF XPLM200} + + { NOTE: Message IDs 1000 - 9999 are allocated to the standard widget classes } + { provided with the library with 1000 - 1099 for widget class 0, 1100 - 1199 } + { for widget class 1, etc. Message IDs 10,000 and beyond are for plugin use. } + ,xpMsg_UserStart = 10000 + + ); + PXPWidgetMessage = ^XPWidgetMessage; + +{___________________________________________________________________________ + * WIDGET CALLBACK FUNCTION + ___________________________________________________________________________} + + { + XPWidgetFunc_t + + This function defines your custom widget's behavior. It will be called by + the widgets library to send messages to your widget. The message and widget + ID are passed in, as well as two ptr-width signed parameters whose meaning + varies with the message. Return 1 to indicate that you have processed the + message, 0 to indicate that you have not. For any message that is not + understood, return 0. + } +TYPE + XPWidgetFunc_t = FUNCTION( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; cdecl; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgetUtils.pas b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgetUtils.pas new file mode 100644 index 0000000..9621126 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgetUtils.pas @@ -0,0 +1,197 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgetUtils; +INTERFACE +{ + ## USAGE NOTES + + The XPWidgetUtils library contains useful functions that make writing and + using widgets less of a pain. + + One set of functions are the widget behavior functions. These functions + each add specific useful behaviors to widgets. They can be used in two + manners: + + 1. You can add a widget behavior function to a widget as a callback proc + using the XPAddWidgetCallback function. The widget will gain that + behavior. Remember that the last function you add has highest priority. + You can use this to change or augment the behavior of an existing + finished widget. + 2. You can call a widget function from inside your own widget function. + This allows you to include useful behaviors in custom-built widgets. A + number of the standard widgets get their behavior from this library. To + do this, call the behavior function from your function first. If it + returns 1, that means it handled the event and you don't need to; simply + return 1. +} + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * GENERAL UTILITIES + ___________________________________________________________________________} + + + { + XPWidgetCreate_t + + This structure contains all of the parameters needed to create a wiget. It + is used with XPUCreateWidgets to create widgets in bulk from an array. All + parameters correspond to those of XPCreateWidget except for the container + index. + + If the container index is equal to the index of a widget in the array, the + widget in the array passed to XPUCreateWidgets is used as the parent of + this widget. Note that if you pass an index greater than your own position + in the array, the parent you are requesting will not exist yet. + + If the container index is NO_PARENT, the parent widget is specified as + NULL. If the container index is PARAM_PARENT, the widget passed into + XPUCreateWidgets is used. + } +TYPE + XPWidgetCreate_t = RECORD + left : Integer; + top : Integer; + right : Integer; + bottom : Integer; + visible : Integer; + descriptor : XPLMString; + { Whether ethis widget is a root wiget } + isRoot : Integer; + { The index of the widget to contain within, or a constant } + containerIndex : Integer; + widgetClass : XPWidgetClass; + END; + PXPWidgetCreate_t = ^XPWidgetCreate_t; + +CONST + NO_PARENT = -1; + + PARAM_PARENT = -2; + + + { + XPUCreateWidgets + + This function creates a series of widgets from a table (see + XPCreateWidget_t above). Pass in an array of widget creation structures and + an array of widget IDs that will receive each widget. + + Widget parents are specified by index into the created widget table, + allowing you to create nested widget structures. You can create multiple + widget trees in one table. Generally you should create widget trees from + the top down. + + You can also pass in a widget ID that will be used when the widget's parent + is listed as PARAM_PARENT; this allows you to embed widgets created with + XPUCreateWidgets in a widget created previously. + } + PROCEDURE XPUCreateWidgets( + inWidgetDefs : PXPWidgetCreate_t; + inCount : Integer; + inParamParent : XPWidgetID; + ioWidgets : PXPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPUMoveWidgetBy + + Simply moves a widget by an amount, +x = right, +y=up, without resizing the + widget. + } + PROCEDURE XPUMoveWidgetBy( + inWidget : XPWidgetID; + inDeltaX : Integer; + inDeltaY : Integer); + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * LAYOUT MANAGERS + ___________________________________________________________________________} +{ + The layout managers are widget behavior functions for handling where + widgets move. Layout managers can be called from a widget function or + attached to a widget later. +} + + + { + XPUFixedLayout + + This function causes the widget to maintain its children in fixed position + relative to itself as it is resized. Use this on the top level 'window' + widget for your window. + } + FUNCTION XPUFixedLayout( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * WIDGET PROC BEHAVIORS + ___________________________________________________________________________} +{ + These widget behavior functions add other useful behaviors to widgets. + These functions cannot be attached to a widget; they must be called from + your widget function. +} + + + { + XPUSelectIfNeeded + + This causes the widget to bring its window to the foreground if it is not + already. inEatClick specifies whether clicks in the background should be + consumed by bringin the window to the foreground. + } + FUNCTION XPUSelectIfNeeded( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inEatClick : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPUDefocusKeyboard + + This causes a click in the widget to send keyboard focus back to X-Plane. + This stops editing of any text fields, etc. + } + FUNCTION XPUDefocusKeyboard( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inEatClick : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPUDragWidget + + XPUDragWidget drags the widget in response to mouse clicks. Pass in not + only the event, but the global coordinates of the drag region, which might + be a sub-region of your widget (for example, a title bar). + } + FUNCTION XPUDragWidget( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgets.pas b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgets.pas new file mode 100644 index 0000000..46ae542 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/Widgets/XPWidgets.pas @@ -0,0 +1,527 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgets; +INTERFACE +{ + ## THEORY OF OPERATION AND NOTES + + Widgets are persistent view 'objects' for X-Plane. A widget is an object + referenced by its opaque handle (widget ID) and the APIs in this file. You + cannot access the widget's guts directly. Every Widget has the following + intrinsic data: + + - A bounding box defined in global screen coordinates with 0,0 in the + bottom left and +y = up, +x = right. + - A visible box, which is the intersection of the bounding box with the + widget's parents visible box. + - Zero or one parent widgets. (Always zero if the widget is a root widget. + - Zero or more child widgets. + - Whether the widget is a root. Root widgets are the top level plugin + windows. + - Whether the widget is visible. + - A text string descriptor, whose meaning varies from widget to widget. + - An arbitrary set of 32 bit integral properties defined by 32-bit integral + keys. This is how specific widgets store specific data. + - A list of widget callbacks proc that implements the widgets behaviors. + + The Widgets library sends messages to widgets to request specific behaviors + or notify the widget of things. + + Widgets may have more than one callback function, in which case messages + are sent to the most recently added callback function until the message is + handled. Messages may also be sent to parents or children; see the + XPWidgetDefs.h header file for the different widget message dispatching + functions. By adding a callback function to a window you can 'subclass' its + behavior. + + A set of standard widgets are provided that serve common UI purposes. You + can also customize or implement entirely custom widgets. + + Widgets are different than other view hierarchies (most notably Win32, + which they bear a striking resemblance to) in the following ways: + + - Not all behavior can be patched. State that is managed by the XPWidgets + DLL and not by individual widgets cannot be customized. + - All coordinates are in global screen coordinates. Coordinates are not + relative to an enclosing widget, nor are they relative to a display + window. + - Widget messages are always dispatched synchronously, and there is no + concept of scheduling an update or a dirty region. Messages originate + from X-Plane as the sim cycle goes by. Since X-Plane is constantly + redrawing, so are widgets; there is no need to mark a part of a widget as + 'needing redrawing' because redrawing happens frequently whether the + widget needs it or not. + - Any widget may be a 'root' widget, causing it to be drawn; there is no + relationship between widget class and rootness. Root widgets are + imlemented as XPLMDisply windows. +} + +USES + XPWidgetDefs, XPLMDisplay; + {$A4} +{___________________________________________________________________________ + * WIDGET CREATION AND MANAGEMENT + ___________________________________________________________________________} + + { + XPCreateWidget + + This function creates a new widget and returns the new widget's ID to you. + If the widget creation fails for some reason, it returns NULL. Widget + creation will fail either if you pass a bad class ID or if there is not + adequate memory. + + Input Parameters: + + - Top, left, bottom, and right in global screen coordinates defining the + widget's location on the screen. + - inVisible is 1 if the widget should be drawn, 0 to start the widget as + hidden. + - inDescriptor is a null terminated string that will become the widget's + descriptor. + - inIsRoot is 1 if this is going to be a root widget, 0 if it will not be. + - inContainer is the ID of this widget's container. It must be 0 for a root + widget. for a non-root widget, pass the widget ID of the widget to place + this widget within. If this widget is not going to start inside another + widget, pass 0; this new widget will then just be floating off in space + (and will not be drawn until it is placed in a widget. + - inClass is the class of the widget to draw. Use one of the predefined + class-IDs to create a standard widget. + + A note on widget embedding: a widget is only called (and will be drawn, + etc.) if it is placed within a widget that will be called. Root widgets are + always called. So it is possible to have whole chains of widgets that are + simply not called. You can preconstruct widget trees and then place them + into root widgets later to activate them if you wish. + } + FUNCTION XPCreateWidget( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inVisible : Integer; + inDescriptor : XPLMString; + inIsRoot : Integer; + inContainer : XPWidgetID; + inClass : XPWidgetClass) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPCreateCustomWidget + + This function is the same as XPCreateWidget except that instead of passing + a class ID, you pass your widget callback function pointer defining the + widget. Use this function to define a custom widget. All parameters are the + same as XPCreateWidget, except that the widget class has been replaced with + the widget function. + } + FUNCTION XPCreateCustomWidget( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inVisible : Integer; + inDescriptor : XPLMString; + inIsRoot : Integer; + inContainer : XPWidgetID; + inCallback : XPWidgetFunc_t) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPDestroyWidget + + This class destroys a widget. Pass in the ID of the widget to kill. If you + pass 1 for inDestroyChilren, the widget's children will be destroyed first, + then this widget will be destroyed. (Furthermore, the widget's children + will be destroyed with the inDestroyChildren flag set to 1, so the + destruction will recurse down the widget tree.) If you pass 0 for this + flag, the child widgets will simply end up with their parent set to 0. + } + PROCEDURE XPDestroyWidget( + inWidget : XPWidgetID; + inDestroyChildren : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPSendMessageToWidget + + This sends any message to a widget. You should probably not go around + simulating the predefined messages that the widgets library defines for + you. You may however define custom messages for your widgets and send them + with this method. + + This method supports several dispatching patterns; see XPDispatchMode for + more info. The function returns 1 if the message was handled, 0 if it was + not. + + For each widget that receives the message (see the dispatching modes), each + widget function from the most recently installed to the oldest one receives + the message in order until it is handled. + } + FUNCTION XPSendMessageToWidget( + inWidget : XPWidgetID; + inMessage : XPWidgetMessage; + inMode : XPDispatchMode; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * WIDGET POSITIONING AND VISIBILITY + ___________________________________________________________________________} + + { + XPPlaceWidgetWithin + + This function changes which container a widget resides in. You may NOT use + this function on a root widget! inSubWidget is the widget that will be + moved. Pass a widget ID in inContainer to make inSubWidget be a child of + inContainer. It will become the last/closest widget in the container. Pass + 0 to remove the widget from any container. Any call to this other than + passing the widget ID of the old parent of the affected widget will cause + the widget to be removed from its old parent. Placing a widget within its + own parent simply makes it the last widget. + + NOTE: this routine does not reposition the sub widget in global + coordinates. If the container has layout management code, it will + reposition the subwidget for you, otherwise you must do it with + SetWidgetGeometry. + } + PROCEDURE XPPlaceWidgetWithin( + inSubWidget : XPWidgetID; + inContainer : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPCountChildWidgets + + This routine returns the number of widgets another widget contains. + } + FUNCTION XPCountChildWidgets( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetNthChildWidget + + This routine returns the widget ID of a child widget by index. Indexes are + 0 based, from 0 to one minus the number of widgets in the parent, + inclusive. If the index is invalid, 0 is returned. + } + FUNCTION XPGetNthChildWidget( + inWidget : XPWidgetID; + inIndex : Integer) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPGetParentWidget + + Returns the parent of a widget, or 0 if the widget has no parent. Root + widgets never have parents and therefore always return 0. + } + FUNCTION XPGetParentWidget( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPShowWidget + + This routine makes a widget visible if it is not already. Note that if a + widget is not in a rooted widget hierarchy or one of its parents is not + visible, it will still not be visible to the user. + } + PROCEDURE XPShowWidget( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPHideWidget + + Makes a widget invisible. See XPShowWidget for considerations of when a + widget might not be visible despite its own visibility state. + } + PROCEDURE XPHideWidget( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPIsWidgetVisible + + This returns 1 if a widget is visible, 0 if it is not. Note that this + routine takes into consideration whether a parent is invisible. Use this + routine to tell if the user can see the widget. + } + FUNCTION XPIsWidgetVisible( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPFindRootWidget + + Returns the Widget ID of the root widget that contains the passed in widget + or NULL if the passed in widget is not in a rooted hierarchy. + } + FUNCTION XPFindRootWidget( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPBringRootWidgetToFront + + This routine makes the specified widget be in the front most widget + hierarchy. If this widget is a root widget, its widget hierarchy comes to + front, otherwise the widget's root is brought to the front. If this widget + is not in an active widget hiearchy (e.g. there is no root widget at the + top of the tree), this routine does nothing. + } + PROCEDURE XPBringRootWidgetToFront( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPIsWidgetInFront + + This routine returns true if this widget's hierarchy is the front most + hierarchy. It returns false if the widget's hierarchy is not in front, or + if the widget is not in a rooted hierarchy. + } + FUNCTION XPIsWidgetInFront( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetGeometry + + This routine returns the bounding box of a widget in global coordinates. + Pass NULL for any parameter you are not interested in. + } + PROCEDURE XPGetWidgetGeometry( + inWidget : XPWidgetID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPSetWidgetGeometry + + This function changes the bounding box of a widget. + } + PROCEDURE XPSetWidgetGeometry( + inWidget : XPWidgetID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetForLocation + + Given a widget and a location, this routine returns the widget ID of the + child of that widget that owns that location. If inRecursive is true then + this will return a child of a child of a widget as it tries to find the + deepest widget at that location. If inVisibleOnly is true, then only + visible widgets are considered, otherwise all widgets are considered. The + widget ID passed for inContainer will be returned if the location is in + that widget but not in a child widget. 0 is returned if the location is not + in the container. + + NOTE: if a widget's geometry extends outside its parents geometry, it will + not be returned by this call for mouse locations outside the parent + geometry. The parent geometry limits the child's eligibility for mouse + location. + } + FUNCTION XPGetWidgetForLocation( + inContainer : XPWidgetID; + inXOffset : Integer; + inYOffset : Integer; + inRecursive : Integer; + inVisibleOnly : Integer) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetExposedGeometry + + This routine returns the bounds of the area of a widget that is completely + within its parent widgets. Since a widget's bounding box can be outside its + parent, part of its area will not be elligible for mouse clicks and should + not draw. Use XPGetWidgetGeometry to find out what area defines your + widget's shape, but use this routine to find out what area to actually draw + into. Note that the widget library does not use OpenGL clipping to keep + frame rates up, although you could use it internally. + } + PROCEDURE XPGetWidgetExposedGeometry( + inWidgetID : XPWidgetID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * ACCESSING WIDGET DATA + ___________________________________________________________________________} + + { + XPSetWidgetDescriptor + + Every widget has a descriptor, which is a text string. What the text string + is used for varies from widget to widget; for example, a push button's text + is its descriptor, a caption shows its descriptor, and a text field's + descriptor is the text being edited. In other words, the usage for the text + varies from widget to widget, but this API provides a universal and + convenient way to get at it. While not all UI widgets need their + descriptor, many do. + } + PROCEDURE XPSetWidgetDescriptor( + inWidget : XPWidgetID; + inDescriptor : XPLMString); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetDescriptor + + This routine returns the widget's descriptor. Pass in the length of the + buffer you are going to receive the descriptor in. The descriptor will be + null terminated for you. This routine returns the length of the actual + descriptor; if you pass NULL for outDescriptor, you can get the + descriptor's length without getting its text. If the length of the + descriptor exceeds your buffer length, the buffer will not be null + terminated (this routine has 'strncpy' semantics). + } + FUNCTION XPGetWidgetDescriptor( + inWidget : XPWidgetID; + outDescriptor : XPLMString; + inMaxDescLength : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetUnderlyingWindow + + Returns the window (from the XPLMDisplay API) that backs your widget + window. If you have opted in to modern windows, via a call to + XPLMEnableFeature("XPLM_USE_NATIVE_WIDGET_WINDOWS", 1), you can use the + returned window ID for display APIs like XPLMSetWindowPositioningMode(), + allowing you to pop the widget window out into a real OS window, or move it + into VR. + } + FUNCTION XPGetWidgetUnderlyingWindow( + inWidget : XPWidgetID) : XPLMWindowID; + cdecl; external XPWIDGETS.DLL; + + { + XPSetWidgetProperty + + This function sets a widget's property. Properties are arbitrary values + associated by a widget by ID. + } + PROCEDURE XPSetWidgetProperty( + inWidget : XPWidgetID; + inProperty : XPWidgetPropertyID; + inValue : intptr_t); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetProperty + + This routine returns the value of a widget's property, or 0 if the property + is not defined. If you need to know whether the property is defined, pass a + pointer to an int for inExists; the existence of that property will be + returned in the int. Pass NULL for inExists if you do not need this + information. + } + FUNCTION XPGetWidgetProperty( + inWidget : XPWidgetID; + inProperty : XPWidgetPropertyID; + inExists : PInteger) : intptr_t; { Can be nil } + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * KEYBOARD MANAGEMENT + ___________________________________________________________________________} + + { + XPSetKeyboardFocus + + Controls which widget will receive keystrokes. Pass the widget ID of the + widget to get the keys. Note that if the widget does not care about + keystrokes, they will go to the parent widget, and if no widget cares about + them, they go to X-Plane. + + If you set the keyboard focus to widget ID 0, X-Plane gets keyboard focus. + + This routine returns the widget ID that ended up with keyboard focus, or 0 + for X-Plane. + + Keyboard focus is not changed if the new widget will not accept it. For + setting to X-Plane, keyboard focus is always accepted. + } + FUNCTION XPSetKeyboardFocus( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPLoseKeyboardFocus + + This causes the specified widget to lose focus; focus is passed to its + parent, or the next parent that will accept it. This routine does nothing + if this widget does not have focus. + } + PROCEDURE XPLoseKeyboardFocus( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetWithFocus + + This routine returns the widget that has keyboard focus, or 0 if X-Plane + has keyboard focus or some other plugin window that does not have widgets + has focus. + } + FUNCTION XPGetWidgetWithFocus: XPWidgetID; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * CREATING CUSTOM WIDGETS + ___________________________________________________________________________} + + { + XPAddWidgetCallback + + This function adds a new widget callback to a widget. This widget callback + supercedes any existing ones and will receive messages first; if it does + not handle messages they will go on to be handled by pre-existing widgets. + + The widget function will remain on the widget for the life of the widget. + The creation message will be sent to the new callback immediately with the + widget ID, and the destruction message will be sent before the other widget + function receives a destruction message. + + This provides a way to 'subclass' an existing widget. By providing a second + hook that only handles certain widget messages, you can customize or extend + widget behavior. + } + PROCEDURE XPAddWidgetCallback( + inWidget : XPWidgetID; + inNewCallback : XPWidgetFunc_t); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetClassFunc + + Given a widget class, this function returns the callbacks that power that + widget class. + } + FUNCTION XPGetWidgetClassFunc( + inWidgetClass : XPWidgetClass) : XPWidgetFunc_t; + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMCamera.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMCamera.pas new file mode 100644 index 0000000..ad76fa4 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMCamera.pas @@ -0,0 +1,155 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMCamera; +INTERFACE +{ + The XPLMCamera APIs allow plug-ins to control the camera angle in X-Plane. + This has a number of applications, including but not limited to: + + - Creating new views (including dynamic/user-controllable views) for the + user. + - Creating applications that use X-Plane as a renderer of scenery, + aircrafts, or both. + + The camera is controlled via six parameters: a location in OpenGL + coordinates and pitch, roll and yaw, similar to an airplane's position. + OpenGL coordinate info is described in detail in the XPLMGraphics + documentation; generally you should use the XPLMGraphics routines to + convert from world to local coordinates. The camera's orientation starts + facing level with the ground directly up the negative-Z axis (approximately + north) with the horizon horizontal. It is then rotated clockwise for yaw, + pitched up for positive pitch, and rolled clockwise around the vector it is + looking along for roll. + + You control the camera either either until the user selects a new view or + permanently (the later being similar to how UDP camera control works). You + control the camera by registering a callback per frame from which you + calculate the new camera positions. This guarantees smooth camera motion. + + Use the XPLMDataAccess APIs to get information like the position of the + aircraft, etc. for complex camera positioning. + + Note: if your goal is to move the virtual pilot in the cockpit, this API is + not needed; simply update the datarefs for the pilot's head position. + + For custom exterior cameras, set the camera's mode to an external view + first to get correct sound and 2-d panel behavior. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * CAMERA CONTROL + ___________________________________________________________________________} + + { + XPLMCameraControlDuration + + This enumeration states how long you want to retain control of the camera. + You can retain it indefinitely or until the user selects a new view. + } +TYPE + XPLMCameraControlDuration = ( + { Control the camera until the user picks a new view. } + xplm_ControlCameraUntilViewChanges = 1 + + { Control the camera until your plugin is disabled or another plugin forcably} + { takes control. } + ,xplm_ControlCameraForever = 2 + + ); + PXPLMCameraControlDuration = ^XPLMCameraControlDuration; + + { + XPLMCameraPosition_t + + This structure contains a full specification of the camera. X, Y, and Z are + the camera's position in OpenGL coordiantes; pitch, roll, and yaw are + rotations from a camera facing flat north in degrees. Positive pitch means + nose up, positive roll means roll right, and positive yaw means yaw right, + all in degrees. Zoom is a zoom factor, with 1.0 meaning normal zoom and 2.0 + magnifying by 2x (objects appear larger). + } + XPLMCameraPosition_t = RECORD + x : Single; + y : Single; + z : Single; + pitch : Single; + heading : Single; + roll : Single; + zoom : Single; + END; + PXPLMCameraPosition_t = ^XPLMCameraPosition_t; + + { + XPLMCameraControl_f + + You use an XPLMCameraControl function to provide continuous control over + the camera. You are passed in a structure in which to put the new camera + position; modify it and return 1 to reposition the camera. Return 0 to + surrender control of the camera; camera control will be handled by X-Plane + on this draw loop. The contents of the structure as you are called are + undefined. + + If X-Plane is taking camera control away from you, this function will be + called with inIsLosingControl set to 1 and ioCameraPosition NULL. + } + XPLMCameraControl_f = FUNCTION( + outCameraPosition : PXPLMCameraPosition_t; { Can be nil } + inIsLosingControl : Integer; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMControlCamera + + This function repositions the camera on the next drawing cycle. You must + pass a non-null control function. Specify in inHowLong how long you'd like + control (indefinitely or until a new view mode is set by the user). + } + PROCEDURE XPLMControlCamera( + inHowLong : XPLMCameraControlDuration; + inControlFunc : XPLMCameraControl_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMDontControlCamera + + This function stops you from controlling the camera. If you have a camera + control function, it will not be called with an inIsLosingControl flag. + X-Plane will control the camera on the next cycle. + + For maximum compatibility you should not use this routine unless you are in + posession of the camera. + } + PROCEDURE XPLMDontControlCamera; + cdecl; external XPLM_DLL; + + { + XPLMIsCameraBeingControlled + + This routine returns 1 if the camera is being controlled, zero if it is + not. If it is and you pass in a pointer to a camera control duration, the + current control duration will be returned. + } + FUNCTION XPLMIsCameraBeingControlled( + outCameraControlDuration: PXPLMCameraControlDuration) : Integer; { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMReadCameraPosition + + This function reads the current camera position. + } + PROCEDURE XPLMReadCameraPosition( + outCameraPosition : PXPLMCameraPosition_t); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDataAccess.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDataAccess.pas new file mode 100644 index 0000000..1ad210e --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDataAccess.pas @@ -0,0 +1,690 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDataAccess; +INTERFACE +{ + The data access API gives you a generic, flexible, high performance way to + read and write data to and from X-Plane and other plug-ins. For example, + this API allows you to read and set the nav radios, get the plane location, + determine the current effective graphics frame rate, etc. + + The data access APIs are the way that you read and write data from the sim + as well as other plugins. + + The API works using opaque data references. A data reference is a source of + data; you do not know where it comes from, but once you have it you can + read the data quickly and possibly write it. + + Dataref Lookup + -------------- + + Data references are identified by verbose, permanent string names; by + convention these names use path separates to form a hierarchy of datarefs, + e.g. (sim/cockpit/radios/nav1_freq_hz). The actual opaque numeric value of + the data reference, as returned by the XPLM API, is implementation defined + and changes each time X-Plane is launched; therefore you need to look up + the dataref by path every time your plugin runs. + + The task of looking up a data reference is relatively expensive; look up + your data references once based on the verbose path strings, and save the + opaque data reference value for the duration of your plugin's operation. + Reading and writing data references is relatively fast (the cost is + equivalent to two function calls through function pointers). + + X-Plane publishes over 4000 datarefs; a complete list may be found in the + reference section of the SDK online documentation (from the SDK home page, + choose Documentation). + + Dataref Types + ------------- + + A note on typing: you must know the correct data type to read and write. + APIs are provided for reading and writing data in a number of ways. You can + also double check the data type for a data ref. Automatic type conversion + is not done for you. + + Dataref types are a set, e.g. a dataref can be more than one type. When + this happens, you can choose which API you want to use to read. For + example, it is not uncommon for a dataref to be of type float and double. + This means you can use either XPLMGetDatad or XPLMGetDataf to read it. + + Creating New Datarefs + --------------------- + + X-Plane provides datarefs that come with the sim, but plugins can also + create their own datarefs. A plugin creates a dataref by registering + function callbacks to read and write the dataref. The XPLM will call your + plugin each time some other plugin (or X-Plane) tries to read or write the + dataref. You must provide a read (and optional write) callback for each + data type you support. + + A note for plugins sharing data with other plugins: the load order of + plugins is not guaranteed. To make sure that every plugin publishing data + has published their data references before other plugins try to subscribe, + publish your data references in your start routine but resolve them the + first time your 'enable' routine is called, or the first time they are + needed in code. + + When a plugin that created a dataref is unloaded, it becomes "orphaned". + The dataref handle continues to be usable, but the dataref is not writable, + and reading it will always return 0 (or 0 items for arrays). If the plugin + is reloaded and re-registers the dataref, the handle becomes un-orphaned + and works again. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * READING AND WRITING DATA + ___________________________________________________________________________} +{ + These routines allow you to access data from within X-Plane and sometimes + modify it. +} + + +TYPE + { + XPLMDataRef + + A data ref is an opaque handle to data provided by the simulator or another + plugin. It uniquely identifies one variable (or array of variables) over + the lifetime of your plugin. You never hard code these values; you always + get them from XPLMFindDataRef. + } + XPLMDataRef = pointer; + PXPLMDataRef = ^XPLMDataRef; + + { + XPLMDataTypeID + + This is an enumeration that defines the type of the data behind a data + reference. This allows you to sanity check that the data type matches what + you expect. But for the most part, you will know the type of data you are + expecting from the online documentation. + + Data types each take a bit field; it is legal to have a single dataref be + more than one type of data. Whe this happens, you can pick any matching + get/set API. + } + XPLMDataTypeID = ( + { Data of a type the current XPLM doesn't do. } + xplmType_Unknown = 0 + + { A single 4-byte integer, native endian. } + ,xplmType_Int = 1 + + { A single 4-byte float, native endian. } + ,xplmType_Float = 2 + + { A single 8-byte double, native endian. } + ,xplmType_Double = 4 + + { An array of 4-byte floats, native endian. } + ,xplmType_FloatArray = 8 + + { An array of 4-byte integers, native endian. } + ,xplmType_IntArray = 16 + + { A variable block of data. } + ,xplmType_Data = 32 + + ); + PXPLMDataTypeID = ^XPLMDataTypeID; + + { + XPLMFindDataRef + + Given a c-style string that names the data ref, this routine looks up the + actual opaque XPLMDataRef that you use to read and write the data. The + string names for datarefs are published on the X-Plane SDK web site. + + This function returns NULL if the data ref cannot be found. + + NOTE: this function is relatively expensive; save the XPLMDataRef this + function returns for future use. Do not look up your data ref by string + every time you need to read or write it. + } + FUNCTION XPLMFindDataRef( + inDataRefName : XPLMString) : XPLMDataRef; + cdecl; external XPLM_DLL; + + { + XPLMCanWriteDataRef + + Given a data ref, this routine returns true if you can successfully set the + data, false otherwise. Some datarefs are read-only. + + NOTE: even if a dataref is marked writable, it may not act writable. This + can happen for datarefs that X-Plane writes to on every frame of + simulation. In some cases, the dataref is writable but you have to set a + separate "override" dataref to 1 to stop X-Plane from writing it. + } + FUNCTION XPLMCanWriteDataRef( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMIsDataRefGood + + This function returns true if the passed in handle is a valid dataref that + is not orphaned. + + Note: there is normally no need to call this function; datarefs returned by + XPLMFindDataRef remain valid (but possibly orphaned) unless there is a + complete plugin reload (in which case your plugin is reloaded anyway). + Orphaned datarefs can be safely read and return 0. Therefore you never need + to call XPLMIsDataRefGood to 'check' the safety of a dataref. + (XPLMIsDatarefGood performs some slow checking of the handle validity, so + it has a perormance cost.) + } + FUNCTION XPLMIsDataRefGood( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDataRefTypes + + This routine returns the types of the data ref for accessor use. If a data + ref is available in multiple data types, the bit-wise OR of these types + will be returned. + } + FUNCTION XPLMGetDataRefTypes( + inDataRef : XPLMDataRef) : XPLMDataTypeID; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * DATA ACCESSORS + ___________________________________________________________________________} +{ + These routines read and write the data references. For each supported data + type there is a reader and a writer. + + If the data ref is orphaned or the plugin that provides it is disabled or + there is a type mismatch, the functions that read data will return 0 as a + default value or not modify the passed in memory. The plugins that write + data will not write under these circumstances or if the data ref is + read-only. + + NOTE: to keep the overhead of reading datarefs low, these routines do not + do full validation of a dataref; passing a junk value for a dataref can + result in crashing the sim. The get/set APIs do check for NULL. + + For array-style datarefs, you specify the number of items to read/write and + the offset into the array; the actual number of items read or written is + returned. This may be less to prevent an array-out-of-bounds error. +} + + + { + XPLMGetDatai + + Read an integer data ref and return its value. The return value is the + dataref value or 0 if the dataref is NULL or the plugin is disabled. + } + FUNCTION XPLMGetDatai( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatai + + Write a new value to an integer data ref. This routine is a no-op if the + plugin publishing the dataref is disabled, the dataref is NULL, or the + dataref is not writable. + } + PROCEDURE XPLMSetDatai( + inDataRef : XPLMDataRef; + inValue : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDataf + + Read a single precision floating point dataref and return its value. The + return value is the dataref value or 0.0 if the dataref is NULL or the + plugin is disabled. + } + FUNCTION XPLMGetDataf( + inDataRef : XPLMDataRef) : Single; + cdecl; external XPLM_DLL; + + { + XPLMSetDataf + + Write a new value to a single precision floating point data ref. This + routine is a no-op if the plugin publishing the dataref is disabled, the + dataref is NULL, or the dataref is not writable. + } + PROCEDURE XPLMSetDataf( + inDataRef : XPLMDataRef; + inValue : Single); + cdecl; external XPLM_DLL; + + { + XPLMGetDatad + + Read a double precision floating point dataref and return its value. The + return value is the dataref value or 0.0 if the dataref is NULL or the + plugin is disabled. + } + FUNCTION XPLMGetDatad( + inDataRef : XPLMDataRef) : Real; + cdecl; external XPLM_DLL; + + { + XPLMSetDatad + + Write a new value to a double precision floating point data ref. This + routine is a no-op if the plugin publishing the dataref is disabled, the + dataref is NULL, or the dataref is not writable. + } + PROCEDURE XPLMSetDatad( + inDataRef : XPLMDataRef; + inValue : Real); + cdecl; external XPLM_DLL; + + { + XPLMGetDatavi + + Read a part of an integer array dataref. If you pass NULL for outValues, + the routine will return the size of the array, ignoring inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatavi( + inDataRef : XPLMDataRef; + outValues : PInteger; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatavi + + Write part or all of an integer array dataref. The values passed by + inValues are written into the dataref starting at inOffset. Up to inCount + values are written; however if the values would write "off the end" of the + dataref array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatavi( + inDataRef : XPLMDataRef; + inValues : PInteger; + inoffset : Integer; + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDatavf + + Read a part of a single precision floating point array dataref. If you pass + NULL for outVaules, the routine will return the size of the array, ignoring + inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatavf( + inDataRef : XPLMDataRef; + outValues : PSingle; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatavf + + Write part or all of a single precision floating point array dataref. The + values passed by inValues are written into the dataref starting at + inOffset. Up to inCount values are written; however if the values would + write "off the end" of the dataref array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatavf( + inDataRef : XPLMDataRef; + inValues : PSingle; + inoffset : Integer; + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDatab + + Read a part of a byte array dataref. If you pass NULL for outVaules, the + routine will return the size of the array, ignoring inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatab( + inDataRef : XPLMDataRef; + outValue : pointer; { Can be nil } + inOffset : Integer; + inMaxBytes : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatab + + Write part or all of a byte array dataref. The values passed by inValues + are written into the dataref starting at inOffset. Up to inCount values are + written; however if the values would write "off the end" of the dataref + array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatab( + inDataRef : XPLMDataRef; + inValue : pointer; + inOffset : Integer; + inLength : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * PUBLISHING YOUR PLUGIN'S DATA + ___________________________________________________________________________} +{ + These functions allow you to create data references that other plug-ins and + X-Plane can access via the above data access APIs. Data references + published by other plugins operate the same as ones published by X-Plane in + all manners except that your data reference will not be available to other + plugins if/when your plugin is disabled. + + You share data by registering data provider callback functions. When a + plug-in requests your data, these callbacks are then called. You provide + one callback to return the value when a plugin 'reads' it and another to + change the value when a plugin 'writes' it. + + Important: you must pick a prefix for your datarefs other than "sim/" - + this prefix is reserved for X-Plane. The X-Plane SDK website contains a + registry where authors can select a unique first word for dataref names, to + prevent dataref collisions between plugins. +} + + + { + XPLMGetDatai_f + + Data provider function pointers. + + These define the function pointers you provide to get or set data. Note + that you are passed a generic pointer for each one. This is the same + pointer you pass in your register routine; you can use it to locate plugin + variables, etc. + + The semantics of your callbacks are the same as the dataref accessor above + - basically routines like XPLMGetDatai are just pass-throughs from a caller + to your plugin. Be particularly mindful in implementing array dataref + read-write accessors; you are responsible for avoiding overruns, supporting + offset read/writes, and handling a read with a NULL buffer. + } +TYPE + XPLMGetDatai_f = FUNCTION( + inRefcon : pointer) : Integer; cdecl; + + { + XPLMSetDatai_f + } + XPLMSetDatai_f = PROCEDURE( + inRefcon : pointer; + inValue : Integer); cdecl; + + { + XPLMGetDataf_f + } + XPLMGetDataf_f = FUNCTION( + inRefcon : pointer) : Single; cdecl; + + { + XPLMSetDataf_f + } + XPLMSetDataf_f = PROCEDURE( + inRefcon : pointer; + inValue : Single); cdecl; + + { + XPLMGetDatad_f + } + XPLMGetDatad_f = FUNCTION( + inRefcon : pointer) : Real; cdecl; + + { + XPLMSetDatad_f + } + XPLMSetDatad_f = PROCEDURE( + inRefcon : pointer; + inValue : Real); cdecl; + + { + XPLMGetDatavi_f + } + XPLMGetDatavi_f = FUNCTION( + inRefcon : pointer; + outValues : PInteger; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; cdecl; + + { + XPLMSetDatavi_f + } + XPLMSetDatavi_f = PROCEDURE( + inRefcon : pointer; + inValues : PInteger; + inOffset : Integer; + inCount : Integer); cdecl; + + { + XPLMGetDatavf_f + } + XPLMGetDatavf_f = FUNCTION( + inRefcon : pointer; + outValues : PSingle; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; cdecl; + + { + XPLMSetDatavf_f + } + XPLMSetDatavf_f = PROCEDURE( + inRefcon : pointer; + inValues : PSingle; + inOffset : Integer; + inCount : Integer); cdecl; + + { + XPLMGetDatab_f + } + XPLMGetDatab_f = FUNCTION( + inRefcon : pointer; + outValue : pointer; { Can be nil } + inOffset : Integer; + inMaxLength : Integer) : Integer; cdecl; + + { + XPLMSetDatab_f + } + XPLMSetDatab_f = PROCEDURE( + inRefcon : pointer; + inValue : pointer; + inOffset : Integer; + inLength : Integer); cdecl; + + { + XPLMRegisterDataAccessor + + This routine creates a new item of data that can be read and written. Pass + in the data's full name for searching, the type(s) of the data for + accessing, and whether the data can be written to. For each data type you + support, pass in a read accessor function and a write accessor function if + necessary. Pass NULL for data types you do not support or write accessors + if you are read-only. + + You are returned a data ref for the new item of data created. You can use + this data ref to unregister your data later or read or write from it. + } + FUNCTION XPLMRegisterDataAccessor( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inIsWritable : Integer; + inReadInt : XPLMGetDatai_f; + inWriteInt : XPLMSetDatai_f; + inReadFloat : XPLMGetDataf_f; + inWriteFloat : XPLMSetDataf_f; + inReadDouble : XPLMGetDatad_f; + inWriteDouble : XPLMSetDatad_f; + inReadIntArray : XPLMGetDatavi_f; + inWriteIntArray : XPLMSetDatavi_f; + inReadFloatArray : XPLMGetDatavf_f; + inWriteFloatArray : XPLMSetDatavf_f; + inReadData : XPLMGetDatab_f; + inWriteData : XPLMSetDatab_f; + inReadRefcon : pointer; + inWriteRefcon : pointer) : XPLMDataRef; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterDataAccessor + + Use this routine to unregister any data accessors you may have registered. + You unregister a data ref by the XPLMDataRef you get back from + registration. Once you unregister a data ref, your function pointer will + not be called anymore. + } + PROCEDURE XPLMUnregisterDataAccessor( + inDataRef : XPLMDataRef); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * SHARING DATA BETWEEN MULTIPLE PLUGINS + ___________________________________________________________________________} +{ + The data reference registration APIs from the previous section allow a + plugin to publish data in a one-owner manner; the plugin that publishes the + data reference owns the real memory that the data ref uses. This is + satisfactory for most cases, but there are also cases where plugnis need to + share actual data. + + With a shared data reference, no one plugin owns the actual memory for the + data reference; the plugin SDK allocates that for you. When the first + plugin asks to 'share' the data, the memory is allocated. When the data is + changed, every plugin that is sharing the data is notified. + + Shared data references differ from the 'owned' data references from the + previous section in a few ways: + + * With shared data references, any plugin can create the data reference; + with owned plugins one plugin must create the data reference and others + subscribe. (This can be a problem if you don't know which set of plugins + will be present). + + * With shared data references, every plugin that is sharing the data is + notified when the data is changed. With owned data references, only the + one owner is notified when the data is changed. + + * With shared data references, you cannot access the physical memory of the + data reference; you must use the XPLMGet... and XPLMSet... APIs. With an + owned data reference, the one owning data reference can manipulate the + data reference's memory in any way it sees fit. + + Shared data references solve two problems: if you need to have a data + reference used by several plugins but do not know which plugins will be + installed, or if all plugins sharing data need to be notified when that + data is changed, use shared data references. +} + + + { + XPLMDataChanged_f + + An XPLMDataChanged_f is a callback that the XPLM calls whenever any other + plug-in modifies shared data. A refcon you provide is passed back to help + identify which data is being changed. In response, you may want to call one + of the XPLMGetDataxxx routines to find the new value of the data. + } +TYPE + XPLMDataChanged_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMShareData + + This routine connects a plug-in to shared data, creating the shared data if + necessary. inDataName is a standard path for the data ref, and inDataType + specifies the type. This function will create the data if it does not + exist. If the data already exists but the type does not match, an error is + returned, so it is important that plug-in authors collaborate to establish + public standards for shared data. + + If a notificationFunc is passed in and is not NULL, that notification + function will be called whenever the data is modified. The notification + refcon will be passed to it. This allows your plug-in to know which shared + data was changed if multiple shared data are handled by one callback, or if + the plug-in does not use global variables. + + A one is returned for successfully creating or finding the shared data; a + zero if the data already exists but is of the wrong type. + } + FUNCTION XPLMShareData( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inNotificationFunc : XPLMDataChanged_f; + inNotificationRefcon: pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnshareData + + This routine removes your notification function for shared data. Call it + when done with the data to stop receiving change notifications. Arguments + must match XPLMShareData. The actual memory will not necessarily be freed, + since other plug-ins could be using it. + } + FUNCTION XPLMUnshareData( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inNotificationFunc : XPLMDataChanged_f; + inNotificationRefcon: pointer) : Integer; + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDefs.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDefs.pas new file mode 100644 index 0000000..91bd774 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDefs.pas @@ -0,0 +1,438 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDefs; +INTERFACE +{ + This file is contains the cross-platform and basic definitions for the + X-Plane SDK. + + The preprocessor macros APL and IBM must be defined to specify the + compilation target; define APL to 1 and IBM 0 to compile on Macintosh and + APL to 0 and IBM to 1 for Windows. You must specify these macro definitions + before including XPLMDefs.h or any other XPLM headers. You can do this + using the -D command line option or a preprocessor header. +} + + {$A4} +{$IFDEF LINUX} + {$DEFINE KYLIX} +{$ENDIF} +TYPE +{$IFNDEF DELPHI} +{$IFNDEF KYLIX} + Pchar = ^char; + Ppchar = ^Pchar; + Psingle = ^single; + Pinteger = ^integer; +{$ENDIF} +{$ENDIF} + Preal = ^real; + Plongint = ^longint; +{___________________________________________________________________________ + * DLL Definitions + ___________________________________________________________________________} +{ + These definitions control the importing and exporting of functions within + the DLL. + + You can prefix your five required callbacks with the PLUGIN_API macro to + declare them as exported C functions. The XPLM_API macro identifies + functions that are provided to you via the plugin SDK. (Link against + XPLM.lib to use these functions.) +} + + + +{___________________________________________________________________________ + * GLOBAL DEFINITIONS + ___________________________________________________________________________} +{ + These definitions are used in all parts of the SDK. +} + + +TYPE + { + XPLMPluginID + + Each plug-in is identified by a unique integer ID. This ID can be used to + disable or enable a plug-in, or discover what plug-in is 'running' at the + time. A plug-in ID is unique within the currently running instance of + X-Plane unless plug-ins are reloaded. Plug-ins may receive a different + unique ID each time they are loaded. This includes the unloading and + reloading of plugins that are part of the user's aircraft. + + For persistent identification of plug-ins, use XPLMFindPluginBySignature in + XPLMUtiltiies.h + + -1 indicates no plug-in. + } + XPLMPluginID = Integer; + PXPLMPluginID = ^XPLMPluginID; + +CONST + { No plugin. } + XPLM_NO_PLUGIN_ID = (-1); + + { X-Plane itself } + XPLM_PLUGIN_XPLANE = (0); + + { The current XPLM revision is 3.03 (303). } + kXPLM_Version = (303); + + { + XPLMKeyFlags + + These bitfields define modifier keys in a platform independent way. When a + key is pressed, a series of messages are sent to your plugin. The down + flag is set in the first of these messages, and the up flag in the last. + While the key is held down, messages are sent with neither to indicate that + the key is being held down as a repeated character. + + The control flag is mapped to the control flag on Macintosh and PC. + Generally X-Plane uses the control key and not the command key on + Macintosh, providing a consistent interface across platforms that does not + necessarily match the Macintosh user interface guidelines. There is not + yet a way for plugins to access the Macintosh control keys without using + #ifdefed code. + } +TYPE + XPLMKeyFlags = ( + { The shift key is down } + xplm_ShiftFlag = 1 + + { The option or alt key is down } + ,xplm_OptionAltFlag = 2 + + { The control key is down* } + ,xplm_ControlFlag = 4 + + { The key is being pressed down } + ,xplm_DownFlag = 8 + + { The key is being released } + ,xplm_UpFlag = 16 + + ); + PXPLMKeyFlags = ^XPLMKeyFlags; + +{___________________________________________________________________________ + * ASCII CONTROL KEY CODES + ___________________________________________________________________________} +{ + These definitions define how various control keys are mapped to ASCII key + codes. Not all key presses generate an ASCII value, so plugin code should + be prepared to see null characters come from the keyboard...this usually + represents a key stroke that has no equivalent ASCII, like a page-down + press. Use virtual key codes to find these key strokes. + + ASCII key codes take into account modifier keys; shift keys will affect + capitals and punctuation; control key combinations may have no vaild ASCII + and produce NULL. To detect control-key combinations, use virtual key + codes, not ASCII keys. +} + + +CONST + XPLM_KEY_RETURN = 13; + + XPLM_KEY_ESCAPE = 27; + + XPLM_KEY_TAB = 9; + + XPLM_KEY_DELETE = 8; + + XPLM_KEY_LEFT = 28; + + XPLM_KEY_RIGHT = 29; + + XPLM_KEY_UP = 30; + + XPLM_KEY_DOWN = 31; + + XPLM_KEY_0 = 48; + + XPLM_KEY_1 = 49; + + XPLM_KEY_2 = 50; + + XPLM_KEY_3 = 51; + + XPLM_KEY_4 = 52; + + XPLM_KEY_5 = 53; + + XPLM_KEY_6 = 54; + + XPLM_KEY_7 = 55; + + XPLM_KEY_8 = 56; + + XPLM_KEY_9 = 57; + + XPLM_KEY_DECIMAL = 46; + +{___________________________________________________________________________ + * VIRTUAL KEY CODES + ___________________________________________________________________________} +{ + These are cross-platform defines for every distinct keyboard press on the + computer. Every physical key on the keyboard has a virtual key code. So + the "two" key on the top row of the main keyboard has a different code from + the "two" key on the numeric key pad. But the 'w' and 'W' character are + indistinguishable by virtual key code because they are the same physical + key (one with and one without the shift key). + + Use virtual key codes to detect keystrokes that do not have ASCII + equivalents, allow the user to map the numeric keypad separately from the + main keyboard, and detect control key and other modifier-key combinations + that generate ASCII control key sequences (many of which are not available + directly via character keys in the SDK). + + To assign virtual key codes we started with the Microsoft set but made some + additions and changes. A few differences: + + 1. Modifier keys are not available as virtual key codes. You cannot get + distinct modifier press and release messages. Please do not try to use + modifier keys as regular keys; doing so will almost certainly interfere + with users' abilities to use the native X-Plane key bindings. + 2. Some keys that do not exist on both Mac and PC keyboards are removed. + 3. Do not assume that the values of these keystrokes are interchangeable + with MS v-keys. +} + + +CONST + XPLM_VK_BACK = $08; + + XPLM_VK_TAB = $09; + + XPLM_VK_CLEAR = $0C; + + XPLM_VK_RETURN = $0D; + + XPLM_VK_ESCAPE = $1B; + + XPLM_VK_SPACE = $20; + + XPLM_VK_PRIOR = $21; + + XPLM_VK_NEXT = $22; + + XPLM_VK_END = $23; + + XPLM_VK_HOME = $24; + + XPLM_VK_LEFT = $25; + + XPLM_VK_UP = $26; + + XPLM_VK_RIGHT = $27; + + XPLM_VK_DOWN = $28; + + XPLM_VK_SELECT = $29; + + XPLM_VK_PRINT = $2A; + + XPLM_VK_EXECUTE = $2B; + + XPLM_VK_SNAPSHOT = $2C; + + XPLM_VK_INSERT = $2D; + + XPLM_VK_DELETE = $2E; + + XPLM_VK_HELP = $2F; + + { XPLM_VK_0 thru XPLM_VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) } + XPLM_VK_0 = $30; + + XPLM_VK_1 = $31; + + XPLM_VK_2 = $32; + + XPLM_VK_3 = $33; + + XPLM_VK_4 = $34; + + XPLM_VK_5 = $35; + + XPLM_VK_6 = $36; + + XPLM_VK_7 = $37; + + XPLM_VK_8 = $38; + + XPLM_VK_9 = $39; + + { XPLM_VK_A thru XPLM_VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) } + XPLM_VK_A = $41; + + XPLM_VK_B = $42; + + XPLM_VK_C = $43; + + XPLM_VK_D = $44; + + XPLM_VK_E = $45; + + XPLM_VK_F = $46; + + XPLM_VK_G = $47; + + XPLM_VK_H = $48; + + XPLM_VK_I = $49; + + XPLM_VK_J = $4A; + + XPLM_VK_K = $4B; + + XPLM_VK_L = $4C; + + XPLM_VK_M = $4D; + + XPLM_VK_N = $4E; + + XPLM_VK_O = $4F; + + XPLM_VK_P = $50; + + XPLM_VK_Q = $51; + + XPLM_VK_R = $52; + + XPLM_VK_S = $53; + + XPLM_VK_T = $54; + + XPLM_VK_U = $55; + + XPLM_VK_V = $56; + + XPLM_VK_W = $57; + + XPLM_VK_X = $58; + + XPLM_VK_Y = $59; + + XPLM_VK_Z = $5A; + + XPLM_VK_NUMPAD0 = $60; + + XPLM_VK_NUMPAD1 = $61; + + XPLM_VK_NUMPAD2 = $62; + + XPLM_VK_NUMPAD3 = $63; + + XPLM_VK_NUMPAD4 = $64; + + XPLM_VK_NUMPAD5 = $65; + + XPLM_VK_NUMPAD6 = $66; + + XPLM_VK_NUMPAD7 = $67; + + XPLM_VK_NUMPAD8 = $68; + + XPLM_VK_NUMPAD9 = $69; + + XPLM_VK_MULTIPLY = $6A; + + XPLM_VK_ADD = $6B; + + XPLM_VK_SEPARATOR = $6C; + + XPLM_VK_SUBTRACT = $6D; + + XPLM_VK_DECIMAL = $6E; + + XPLM_VK_DIVIDE = $6F; + + XPLM_VK_F1 = $70; + + XPLM_VK_F2 = $71; + + XPLM_VK_F3 = $72; + + XPLM_VK_F4 = $73; + + XPLM_VK_F5 = $74; + + XPLM_VK_F6 = $75; + + XPLM_VK_F7 = $76; + + XPLM_VK_F8 = $77; + + XPLM_VK_F9 = $78; + + XPLM_VK_F10 = $79; + + XPLM_VK_F11 = $7A; + + XPLM_VK_F12 = $7B; + + XPLM_VK_F13 = $7C; + + XPLM_VK_F14 = $7D; + + XPLM_VK_F15 = $7E; + + XPLM_VK_F16 = $7F; + + XPLM_VK_F17 = $80; + + XPLM_VK_F18 = $81; + + XPLM_VK_F19 = $82; + + XPLM_VK_F20 = $83; + + XPLM_VK_F21 = $84; + + XPLM_VK_F22 = $85; + + XPLM_VK_F23 = $86; + + XPLM_VK_F24 = $87; + + { The following definitions are extended and are not based on the Microsoft } + { key set. } + XPLM_VK_EQUAL = $B0; + + XPLM_VK_MINUS = $B1; + + XPLM_VK_RBRACE = $B2; + + XPLM_VK_LBRACE = $B3; + + XPLM_VK_QUOTE = $B4; + + XPLM_VK_SEMICOLON = $B5; + + XPLM_VK_BACKSLASH = $B6; + + XPLM_VK_COMMA = $B7; + + XPLM_VK_SLASH = $B8; + + XPLM_VK_PERIOD = $B9; + + XPLM_VK_BACKQUOTE = $BA; + + XPLM_VK_ENTER = $BB; + + XPLM_VK_NUMPAD_ENT = $BC; + + XPLM_VK_NUMPAD_EQ = $BD; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDisplay.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDisplay.pas new file mode 100644 index 0000000..a100fd0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMDisplay.pas @@ -0,0 +1,1452 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDisplay; +INTERFACE +{ + This API provides the basic hooks to draw in X-Plane and create user + interface. All X-Plane drawing is done in OpenGL. The X-Plane plug-in + manager takes care of properly setting up the OpenGL context and matrices. + You do not decide when in your code's execution to draw; X-Plane tells you + (via callbacks) when it is ready to have your plugin draw. + + X-Plane's drawing strategy is straightforward: every "frame" the screen is + rendered by drawing the 3-D scene (dome, ground, objects, airplanes, etc.) + and then drawing the cockpit on top of it. Alpha blending is used to + overlay the cockpit over the world (and the gauges over the panel, etc.). + X-Plane user interface elements (including windows like the map, the main + menu, etc.) are then drawn on top of the cockpit. + + There are two ways you can draw: directly and in a window. + + Direct drawing (deprecated!---more on that below) involves drawing to the + screen before or after X-Plane finishes a phase of drawing. When you draw + directly, you can specify whether X-Plane is to complete this phase or not. + This allows you to do three things: draw before X-Plane does (under it), + draw after X-Plane does (over it), or draw instead of X-Plane. + + To draw directly, you register a callback and specify which phase you want + to intercept. The plug-in manager will call you over and over to draw that + phase. + + Direct drawing allows you to override scenery, panels, or anything. Note + that you cannot assume that you are the only plug-in drawing at this phase. + + Direct drawing is deprecated; at some point in the X-Plane 11 run, it will + likely become unsupported entirely as X-Plane transitions from OpenGL to + modern graphics API backends (e.g., Vulkan, Metal, etc.). In the long term, + plugins should use the XPLMInstance API for drawing 3-D objects---this will + be much more efficient than general 3-D OpenGL drawing, and it will + actually be supported by the new graphics backends. We do not yet know what + the post-transition API for generic 3-D drawing will look like (if it + exists at all). + + In contrast to direct drawing, window drawing provides a higher level + functionality. With window drawing, you create a 2-D window that takes up a + portion of the screen. Window drawing is always two dimensional. Window + drawing is front-to-back controlled; you can specify that you want your + window to be brought on top, and other plug-ins may put their window on top + of you. Window drawing also allows you to sign up for key presses and + receive mouse clicks. + + There are three ways to get keystrokes: + + 1. If you create a window, the window can take keyboard focus. It will + then receive all keystrokes. If no window has focus, X-Plane receives + keystrokes. Use this to implement typing in dialog boxes, etc. Only + one window may have focus at a time; your window will be notified if it + loses focus. + 2. If you need low level access to the keystroke stream, install a key + sniffer. Key sniffers can be installed above everything or right in + front of the sim. + 3. If you would like to associate key strokes with commands/functions in + your plug-in, you should simply register a command (via + XPLMCreateCommand()) and allow users to bind whatever key they choose to + that command. Another (now deprecated) method of doing so is to use a + hot key---a key-specific callback. Hotkeys are sent based on virtual + key strokes, so any key may be distinctly mapped with any modifiers. + Hot keys can be remapped by other plug-ins. As a plug-in, you don't + have to worry about what your hot key ends up mapped to; other plug-ins + may provide a UI for remapping keystrokes. So hotkeys allow a user to + resolve conflicts and customize keystrokes. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * DRAWING CALLBACKS + ___________________________________________________________________________} +{ + Basic drawing callbacks, for low level intercepting of X-Plane's render + loop. The purpose of drawing callbacks is to provide targeted additions or + replacements to X-Plane's graphics environment (for example, to add extra + custom objects, or replace drawing of the AI aircraft). Do not assume that + the drawing callbacks will be called in the order implied by the + enumerations. Also do not assume that each drawing phase ends before + another begins; they may be nested. + + Note that all APIs in this section are deprecated, and will likely be + removed during the X-Plane 11 run as part of the transition to + Vulkan/Metal/etc. See the XPLMInstance API for future-proof drawing of 3-D + objects. +} + + + { + XPLMDrawingPhase + + This constant indicates which part of drawing we are in. Drawing is done + from the back to the front. We get a callback before or after each item. + Metaphases provide access to the beginning and end of the 3d (scene) and + 2d (cockpit) drawing in a manner that is independent of new phases added + via X-Plane implementation. + + **NOTE**: As of XPLM302 the legacy 3D drawing phases (xplm_Phase_FirstScene + to xplm_Phase_LastScene) are deprecated. When running under X-Plane 11.50 + with the modern Vulkan or Metal backend, X-Plane will no longer call + these drawing phases. There is a new drawing phase, xplm_Phase_Modern3D, + which is supported under OpenGL and Vulkan which is called out roughly + where the old before xplm_Phase_Airplanes phase was for blending. This + phase is *NOT* supported under Metal and comes with potentially + substantial performance overhead. Please do *NOT* opt into this phase if + you don't do any actual drawing that requires the depth buffer in some + way! + + **WARNING**: As X-Plane's scenery evolves, some drawing phases may cease to + exist and new ones may be invented. If you need a particularly specific + use of these codes, consult Austin and/or be prepared to revise your code + as X-Plane evolves. + } +TYPE + XPLMDrawingPhase = ( +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. This is the earliest point at which you can draw } + { in 3-d. } + xplm_Phase_FirstScene = 0 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing of land and water. } + ,xplm_Phase_Terrain = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing runways and other airport detail. } + ,xplm_Phase_Airports = 10 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing roads, trails, trains, etc. } + ,xplm_Phase_Vectors = 15 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. 3-d objects (houses, smokestacks, etc. } + ,xplm_Phase_Objects = 20 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. External views of airplanes, both yours and the } + { AI aircraft. } + ,xplm_Phase_Airplanes = 25 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. This is the last point at which you can draw in } + { 3-d. } + ,xplm_Phase_LastScene = 30 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM302} + { A chance to do modern 3D drawing. } + ,xplm_Phase_Modern3D = 31 +{$ENDIF XPLM302} + + { This is the first phase where you can draw in 2-d. } + ,xplm_Phase_FirstCockpit = 35 + + { The non-moving parts of the aircraft panel. } + ,xplm_Phase_Panel = 40 + + { The moving parts of the aircraft panel. } + ,xplm_Phase_Gauges = 45 + + { Floating windows from plugins. } + ,xplm_Phase_Window = 50 + + { The last chance to draw in 2d. } + ,xplm_Phase_LastCockpit = 55 + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMap3D = 100 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMap2D = 101 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMapProfile = 102 +{$ENDIF XPLM200} + + ); + PXPLMDrawingPhase = ^XPLMDrawingPhase; + + { + XPLMDrawCallback_f + + This is the prototype for a low level drawing callback. You are passed in + the phase and whether it is before or after. If you are before the phase, + return 1 to let X-Plane draw or 0 to suppress X-Plane drawing. If you are + after the phase the return value is ignored. + + Refcon is a unique value that you specify when registering the callback, + allowing you to slip a pointer to your own data to the callback. + + Upon entry the OpenGL context will be correctly set up for you and OpenGL + will be in 'local' coordinates for 3d drawing and panel coordinates for 2d + drawing. The OpenGL state (texturing, etc.) will be unknown. + } + XPLMDrawCallback_f = FUNCTION( + inPhase : XPLMDrawingPhase; + inIsBefore : Integer; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMRegisterDrawCallback + + This routine registers a low level drawing callback. Pass in the phase you + want to be called for and whether you want to be called before or after. + This routine returns 1 if the registration was successful, or 0 if the + phase does not exist in this version of X-Plane. You may register a + callback multiple times for the same or different phases as long as the + refcon is unique each time. + + Note that this function will likely be removed during the X-Plane 11 run as + part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + future-proof drawing of 3-D objects. + } + FUNCTION XPLMRegisterDrawCallback( + inCallback : XPLMDrawCallback_f; + inPhase : XPLMDrawingPhase; + inWantsBefore : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterDrawCallback + + This routine unregisters a draw callback. You must unregister a callback + for each time you register a callback if you have registered it multiple + times with different refcons. The routine returns 1 if it can find the + callback to unregister, 0 otherwise. + + Note that this function will likely be removed during the X-Plane 11 run as + part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + future-proof drawing of 3-D objects. + } + FUNCTION XPLMUnregisterDrawCallback( + inCallback : XPLMDrawCallback_f; + inPhase : XPLMDrawingPhase; + inWantsBefore : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * WINDOW API + ___________________________________________________________________________} +{ + The window API provides a high-level abstraction for drawing with UI + interaction. + + Windows may operate in one of two modes: legacy (for plugins compiled + against old versions of the XPLM, as well as windows created via the + deprecated XPLMCreateWindow() function, rather than XPLMCreateWindowEx()), + or modern (for windows compiled against the XPLM300 or newer API, and + created via XPLMCreateWindowEx()). + + Modern windows have access to new X-Plane 11 windowing features, like + support for new positioning modes (including being "popped out" into their + own first-class window in the operating system). They can also optionally + be decorated in the style of X-Plane 11 windows (like the map). + + Modern windows operate in "boxel" units. A boxel ("box of pixels") is a + unit of virtual pixels which, depending on X-Plane's scaling, may + correspond to an arbitrary NxN "box" of real pixels on screen. Because + X-Plane handles this scaling automatically, you can effectively treat the + units as though you were simply drawing in pixels, and know that when + X-Plane is running with 150% or 200% scaling, your drawing will be + automatically scaled (and likewise all mouse coordinates, screen bounds, + etc. will also be auto-scaled). + + In contrast, legacy windows draw in true screen pixels, and thus tend to + look quite small when X-Plane is operating in a scaled mode. + + Legacy windows have their origin in the lower left of the main X-Plane + window. In contrast, since modern windows are not constrained to the main + window, they have their origin in the lower left of the entire global + desktop space, and the lower left of the main X-Plane window is not + guaranteed to be (0, 0). In both cases, x increases as you move left, and y + increases as you move up. +} + + +TYPE + { + XPLMWindowID + + This is an opaque identifier for a window. You use it to control your + window. When you create a window (via either XPLMCreateWindow() or + XPLMCreateWindowEx()), you will specify callbacks to handle drawing, mouse + interaction, etc. + } + XPLMWindowID = pointer; + PXPLMWindowID = ^XPLMWindowID; + + { + XPLMDrawWindow_f + + A callback to handle 2-D drawing of your window. You are passed in your + window and its refcon. Draw the window. You can use other XPLM functions + from this header to find the current dimensions of your window, etc. When + this callback is called, the OpenGL context will be set properly for 2-D + window drawing. + + **Note**: Because you are drawing your window over a background, you can + make a translucent window easily by simply not filling in your entire + window's bounds. + } + XPLMDrawWindow_f = PROCEDURE( + inWindowID : XPLMWindowID; + inRefcon : pointer); cdecl; + + { + XPLMHandleKey_f + + This function is called when a key is pressed or keyboard focus is taken + away from your window. If losingFocus is 1, you are losing the keyboard + focus, otherwise a key was pressed and inKey contains its character. You + are also passed your window and a refcon. + + Warning: this API declares virtual keys as a signed character; however the + VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + to an unsigned char to get correct comparisons in C. + } + XPLMHandleKey_f = PROCEDURE( + inWindowID : XPLMWindowID; + inKey : XPLMChar; + inFlags : XPLMKeyFlags; + inVirtualKey : XPLMChar; + inRefcon : pointer; + losingFocus : Integer); cdecl; + + { + XPLMMouseStatus + + When the mouse is clicked, your mouse click routine is called repeatedly. + It is first called with the mouse down message. It is then called zero or + more times with the mouse-drag message, and finally it is called once with + the mouse up message. All of these messages will be directed to the same + window; you are guaranteed to not receive a drag or mouse-up event without + first receiving the corresponding mouse-down. + } + XPLMMouseStatus = ( + xplm_MouseDown = 1 + + ,xplm_MouseDrag = 2 + + ,xplm_MouseUp = 3 + + ); + PXPLMMouseStatus = ^XPLMMouseStatus; + + { + XPLMHandleMouseClick_f + + You receive this call for one of three events: + + - when the user clicks the mouse button down + - (optionally) when the user drags the mouse after a down-click, but before + the up-click + - when the user releases the down-clicked mouse button. + + You receive the x and y of the click, your window, and a refcon. Return 1 + to consume the click, or 0 to pass it through. + + WARNING: passing clicks through windows (as of this writing) causes mouse + tracking problems in X-Plane; do not use this feature! + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleMouseClick_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + inMouse : XPLMMouseStatus; + inRefcon : pointer) : Integer; cdecl; + +{$IFDEF XPLM200} + { + XPLMCursorStatus + + XPLMCursorStatus describes how you would like X-Plane to manage the cursor. + See XPLMHandleCursor_f for more info. + } +TYPE + XPLMCursorStatus = ( + { X-Plane manages the cursor normally, plugin does not affect the cusrsor. } + xplm_CursorDefault = 0 + + { X-Plane hides the cursor. } + ,xplm_CursorHidden = 1 + + { X-Plane shows the cursor as the default arrow. } + ,xplm_CursorArrow = 2 + + { X-Plane shows the cursor but lets you select an OS cursor. } + ,xplm_CursorCustom = 3 + + ); + PXPLMCursorStatus = ^XPLMCursorStatus; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMHandleCursor_f + + The SDK calls your cursor status callback when the mouse is over your + plugin window. Return a cursor status code to indicate how you would like + X-Plane to manage the cursor. If you return xplm_CursorDefault, the SDK + will try lower-Z-order plugin windows, then let the sim manage the cursor. + + Note: you should never show or hide the cursor yourself---these APIs are + typically reference-counted and thus cannot safely and predictably be used + by the SDK. Instead return one of xplm_CursorHidden to hide the cursor or + xplm_CursorArrow/xplm_CursorCustom to show the cursor. + + If you want to implement a custom cursor by drawing a cursor in OpenGL, use + xplm_CursorHidden to hide the OS cursor and draw the cursor using a 2-d + drawing callback (after xplm_Phase_Window is probably a good choice, but + see deprecation warnings on the drawing APIs!). If you want to use a + custom OS-based cursor, use xplm_CursorCustom to ask X-Plane to show the + cursor but not affect its image. You can then use an OS specific call like + SetThemeCursor (Mac) or SetCursor/LoadCursor (Windows). + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleCursor_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + inRefcon : pointer) : XPLMCursorStatus; cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMHandleMouseWheel_f + + The SDK calls your mouse wheel callback when one of the mouse wheels is + scrolled within your window. Return 1 to consume the mouse wheel movement + or 0 to pass them on to a lower window. (If your window appears opaque to + the user, you should consume mouse wheel scrolling even if it does + nothing.) The number of "clicks" indicates how far the wheel was turned + since the last callback. The wheel is 0 for the vertical axis or 1 for the + horizontal axis (for OS/mouse combinations that support this). + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleMouseWheel_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + wheel : Integer; + clicks : Integer; + inRefcon : pointer) : Integer; cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM300} + { + XPLMWindowLayer + + XPLMWindowLayer describes where in the ordering of windows X-Plane should + place a particular window. Windows in higher layers cover windows in lower + layers. So, a given window might be at the top of its particular layer, but + it might still be obscured by a window in a higher layer. (This happens + frequently when floating windows, like X-Plane's map, are covered by a + modal alert.) + + Your window's layer can only be specified when you create the window (in + the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). For this reason, + layering only applies to windows created with new X-Plane 11 GUI features. + (Windows created using the older XPLMCreateWindow(), or windows compiled + against a pre-XPLM300 version of the SDK will simply be placed in the + flight overlay window layer.) + } +TYPE + XPLMWindowLayer = ( + { The lowest layer, used for HUD-like displays while flying. } + xplm_WindowLayerFlightOverlay = 0 + + { Windows that "float" over the sim, like the X-Plane 11 map does. If you are} + { not sure which layer to create your window in, choose floating. } + ,xplm_WindowLayerFloatingWindows = 1 + + { An interruptive modal that covers the sim with a transparent black overlay } + { to draw the user's focus to the alert } + ,xplm_WindowLayerModal = 2 + + { "Growl"-style notifications that are visible in a corner of the screen, } + { even over modals } + ,xplm_WindowLayerGrowlNotifications = 3 + + ); + PXPLMWindowLayer = ^XPLMWindowLayer; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMWindowDecoration + + XPLMWindowDecoration describes how "modern" windows will be displayed. This + impacts both how X-Plane draws your window as well as certain mouse + handlers. + + Your window's decoration can only be specified when you create the window + (in the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). + } +TYPE + XPLMWindowDecoration = ( + { X-Plane will draw no decoration for your window, and apply no automatic } + { click handlers. The window will not stop click from passing through its } + { bounds. This is suitable for "windows" which request, say, the full screen } + { bounds, then only draw in a small portion of the available area. } + xplm_WindowDecorationNone = 0 + + { The default decoration for "native" windows, like the map. Provides a solid} + { background, as well as click handlers for resizing and dragging the window.} + ,xplm_WindowDecorationRoundRectangle = 1 + + { X-Plane will draw no decoration for your window, nor will it provide resize} + { handlers for your window edges, but it will stop clicks from passing } + { through your windows bounds. } + ,xplm_WindowDecorationSelfDecorated = 2 + + { Like self-decorated, but with resizing; X-Plane will draw no decoration for} + { your window, but it will stop clicks from passing through your windows } + { bounds, and provide automatic mouse handlers for resizing. } + ,xplm_WindowDecorationSelfDecoratedResizable = 3 + + ); + PXPLMWindowDecoration = ^XPLMWindowDecoration; +{$ENDIF XPLM301} + +{$IFDEF XPLM200} + { + XPLMCreateWindow_t + + The XPMCreateWindow_t structure defines all of the parameters used to + create a modern window using XPLMCreateWindowEx(). The structure will be + expanded in future SDK APIs to include more features. Always set the + structSize member to the size of your struct in bytes! + + All windows created by this function in the XPLM300 version of the API are + created with the new X-Plane 11 GUI features. This means your plugin will + get to "know" about the existence of X-Plane windows other than the main + window. All drawing and mouse callbacks for your window will occur in + "boxels," giving your windows automatic support for high-DPI scaling in + X-Plane. In addition, your windows can opt-in to decoration with the + X-Plane 11 window styling, and you can use the + XPLMSetWindowPositioningMode() API to make your window "popped out" into a + first-class operating system window. + + Note that this requires dealing with your window's bounds in "global + desktop" positioning units, rather than the traditional panel coordinate + system. In global desktop coordinates, the main X-Plane window may not have + its origin at coordinate (0, 0), and your own window may have negative + coordinates. Assuming you don't implicitly assume (0, 0) as your origin, + the only API change you should need is to start using + XPLMGetMouseLocationGlobal() rather than XPLMGetMouseLocation(), and + XPLMGetScreenBoundsGlobal() instead of XPLMGetScreenSize(). + + If you ask to be decorated as a floating window, you'll get the blue window + control bar and blue backing that you see in X-Plane 11's normal "floating" + windows (like the map). + } +TYPE + XPLMCreateWindow_t = RECORD + { Used to inform XPLMCreateWindowEx() of the SDK version you compiled } + { against; should always be set to sizeof(XPLMCreateWindow_t) } + structSize : Integer; + { Left bound, in global desktop boxels } + left : Integer; + { Top bound, in global desktop boxels } + top : Integer; + { Right bound, in global desktop boxels } + right : Integer; + { Bottom bound, in global desktop boxels } + bottom : Integer; + visible : Integer; + drawWindowFunc : XPLMDrawWindow_f; + { A callback to handle the user left-clicking within your window (or NULL to } + { ignore left clicks) } + handleMouseClickFunc : XPLMHandleMouseClick_f; + handleKeyFunc : XPLMHandleKey_f; + handleCursorFunc : XPLMHandleCursor_f; + handleMouseWheelFunc : XPLMHandleMouseWheel_f; + { A reference which will be passed into each of your window callbacks. Use } + { this to pass information to yourself as needed. } + refcon : pointer; +{$IFDEF XPLM301} + { Specifies the type of X-Plane 11-style "wrapper" you want around your } + { window, if any } + decorateAsFloatingWindow : XPLMWindowDecoration; +{$ENDIF XPLM301} +{$IFDEF XPLM300} + layer : XPLMWindowLayer; +{$ENDIF XPLM300} +{$IFDEF XPLM300} + { A callback to handle the user right-clicking within your window (or NULL to} + { ignore right clicks) } + handleRightClickFunc : XPLMHandleMouseClick_f; +{$ENDIF XPLM300} + END; + PXPLMCreateWindow_t = ^XPLMCreateWindow_t; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMCreateWindowEx + + This routine creates a new "modern" window. You pass in an + XPLMCreateWindow_t structure with all of the fields set in. You must set + the structSize of the structure to the size of the actual structure you + used. Also, you must provide functions for every callback---you may not + leave them null! (If you do not support the cursor or mouse wheel, use + functions that return the default values.) + } + FUNCTION XPLMCreateWindowEx( + inParams : PXPLMCreateWindow_t) : XPLMWindowID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + { + XPLMCreateWindow + + Deprecated as of XPLM300. + + This routine creates a new legacy window. Unlike modern windows (created + via XPLMCreateWindowEx()), legacy windows do not have access to X-Plane 11 + features like automatic scaling for high-DPI screens, native window styles, + or support for being "popped out" into first-class operating system + windows. + + Pass in the dimensions and offsets to the window's bottom left corner from + the bottom left of the screen. You can specify whether the window is + initially visible or not. Also, you pass in three callbacks to run the + window and a refcon. This function returns a window ID you can use to + refer to the new window. + + NOTE: Legacy windows do not have "frames"; you are responsible for drawing + the background and frame of the window. Higher level libraries have + routines which make this easy. + } + FUNCTION XPLMCreateWindow( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inIsVisible : Integer; + inDrawCallback : XPLMDrawWindow_f; + inKeyCallback : XPLMHandleKey_f; + inMouseCallback : XPLMHandleMouseClick_f; + inRefcon : pointer) : XPLMWindowID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyWindow + + This routine destroys a window. The window's callbacks are not called + after this call. Keyboard focus is removed from the window before + destroying it. + } + PROCEDURE XPLMDestroyWindow( + inWindowID : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMGetScreenSize + + This routine returns the size of the main X-Plane OpenGL window in pixels. + This number can be used to get a rough idea of the amount of detail the + user will be able to see when drawing in 3-d. + } + PROCEDURE XPLMGetScreenSize( + outWidth : PInteger; { Can be nil } + outHeight : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetScreenBoundsGlobal + + This routine returns the bounds of the "global" X-Plane desktop, in boxels. + Unlike the non-global version XPLMGetScreenSize(), this is multi-monitor + aware. There are three primary consequences of multimonitor awareness. + + First, if the user is running X-Plane in full-screen on two or more + monitors (typically configured using one full-screen window per monitor), + the global desktop will be sized to include all X-Plane windows. + + Second, the origin of the screen coordinates is not guaranteed to be (0, + 0). Suppose the user has two displays side-by-side, both running at 1080p. + Suppose further that they've configured their OS to make the left display + their "primary" monitor, and that X-Plane is running in full-screen on + their right monitor only. In this case, the global desktop bounds would be + the rectangle from (1920, 0) to (3840, 1080). If the user later asked + X-Plane to draw on their primary monitor as well, the bounds would change + to (0, 0) to (3840, 1080). + + Finally, if the usable area of the virtual desktop is not a perfect + rectangle (for instance, because the monitors have different resolutions or + because one monitor is configured in the operating system to be above and + to the right of the other), the global desktop will include any wasted + space. Thus, if you have two 1080p monitors, and monitor 2 is configured to + have its bottom left touch monitor 1's upper right, your global desktop + area would be the rectangle from (0, 0) to (3840, 2160). + + Note that popped-out windows (windows drawn in their own operating system + windows, rather than "floating" within X-Plane) are not included in these + bounds. + } + PROCEDURE XPLMGetScreenBoundsGlobal( + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMReceiveMonitorBoundsGlobal_f + + This function is informed of the global bounds (in boxels) of a particular + monitor within the X-Plane global desktop space. Note that X-Plane must be + running in full screen on a monitor in order for that monitor to be passed + to you in this callback. + } +TYPE + XPLMReceiveMonitorBoundsGlobal_f = PROCEDURE( + inMonitorIndex : Integer; + inLeftBx : Integer; + inTopBx : Integer; + inRightBx : Integer; + inBottomBx : Integer; + inRefcon : pointer); cdecl; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMGetAllMonitorBoundsGlobal + + This routine immediately calls you back with the bounds (in boxels) of each + full-screen X-Plane window within the X-Plane global desktop space. Note + that if a monitor is *not* covered by an X-Plane window, you cannot get its + bounds this way. Likewise, monitors with only an X-Plane window (not in + full-screen mode) will not be included. + + If X-Plane is running in full-screen and your monitors are of the same size + and configured contiguously in the OS, then the combined global bounds of + all full-screen monitors will match the total global desktop bounds, as + returned by XPLMGetScreenBoundsGlobal(). (Of course, if X-Plane is running + in windowed mode, this will not be the case. Likewise, if you have + differently sized monitors, the global desktop space will include wasted + space.) + + Note that this function's monitor indices match those provided by + XPLMGetAllMonitorBoundsOS(), but the coordinates are different (since the + X-Plane global desktop may not match the operating system's global desktop, + and one X-Plane boxel may be larger than one pixel due to 150% or 200% + scaling). + } + PROCEDURE XPLMGetAllMonitorBoundsGlobal( + inMonitorBoundsCallback: XPLMReceiveMonitorBoundsGlobal_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMReceiveMonitorBoundsOS_f + + This function is informed of the global bounds (in pixels) of a particular + monitor within the operating system's global desktop space. Note that a + monitor index being passed to you here does not indicate that X-Plane is + running in full screen on this monitor, or even that any X-Plane windows + exist on this monitor. + } +TYPE + XPLMReceiveMonitorBoundsOS_f = PROCEDURE( + inMonitorIndex : Integer; + inLeftPx : Integer; + inTopPx : Integer; + inRightPx : Integer; + inBottomPx : Integer; + inRefcon : pointer); cdecl; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMGetAllMonitorBoundsOS + + This routine immediately calls you back with the bounds (in pixels) of each + monitor within the operating system's global desktop space. Note that + unlike XPLMGetAllMonitorBoundsGlobal(), this may include monitors that have + no X-Plane window on them. + + Note that this function's monitor indices match those provided by + XPLMGetAllMonitorBoundsGlobal(), but the coordinates are different (since + the X-Plane global desktop may not match the operating system's global + desktop, and one X-Plane boxel may be larger than one pixel). + } + PROCEDURE XPLMGetAllMonitorBoundsOS( + inMonitorBoundsCallback: XPLMReceiveMonitorBoundsOS_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetMouseLocation + + Deprecated in XPLM300. Modern windows should use + XPLMGetMouseLocationGlobal() instead. + + This routine returns the current mouse location in pixels relative to the + main X-Plane window. The bottom left corner of the main window is (0, 0). + Pass NULL to not receive info about either parameter. + + Because this function gives the mouse position relative to the main X-Plane + window (rather than in global bounds), this function should only be used by + legacy windows. Modern windows should instead get the mouse position in + global desktop coordinates using XPLMGetMouseLocationGlobal(). + + Note that unlike XPLMGetMouseLocationGlobal(), if the mouse goes outside + the user's main monitor (for instance, to a pop out window or a secondary + monitor), this function will not reflect it. + } + PROCEDURE XPLMGetMouseLocation( + outX : PInteger; { Can be nil } + outY : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetMouseLocationGlobal + + Returns the current mouse location in global desktop boxels. Unlike + XPLMGetMouseLocation(), the bottom left of the main X-Plane window is not + guaranteed to be (0, 0)---instead, the origin is the lower left of the + entire global desktop space. In addition, this routine gives the real mouse + location when the mouse goes to X-Plane windows other than the primary + display. Thus, it can be used with both pop-out windows and secondary + monitors. + + This is the mouse location function to use with modern windows (i.e., those + created by XPLMCreateWindowEx()). + + Pass NULL to not receive info about either parameter. + } + PROCEDURE XPLMGetMouseLocationGlobal( + outX : PInteger; { Can be nil } + outY : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetWindowGeometry + + This routine returns the position and size of a window. The units and + coordinate system vary depending on the type of window you have. + + If this is a legacy window (one compiled against a pre-XPLM300 version of + the SDK, or an XPLM300 window that was not created using + XPLMCreateWindowEx()), the units are pixels relative to the main X-Plane + display. + + If, on the other hand, this is a new X-Plane 11-style window (compiled + against the XPLM300 SDK and created using XPLMCreateWindowEx()), the units + are global desktop boxels. + + Pass NULL to not receive any paramter. + } + PROCEDURE XPLMGetWindowGeometry( + inWindowID : XPLMWindowID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetWindowGeometry + + This routine allows you to set the position and size of a window. + + The units and coordinate system match those of XPLMGetWindowGeometry(). + That is, modern windows use global desktop boxel coordinates, while legacy + windows use pixels relative to the main X-Plane display. + + Note that this only applies to "floating" windows (that is, windows that + are drawn within the X-Plane simulation windows, rather than being "popped + out" into their own first-class operating system windows). To set the + position of windows whose positioning mode is xplm_WindowPopOut, you'll + need to instead use XPLMSetWindowGeometryOS(). + } + PROCEDURE XPLMSetWindowGeometry( + inWindowID : XPLMWindowID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetWindowGeometryOS + + This routine returns the position and size of a "popped out" window (i.e., + a window whose positioning mode is xplm_WindowPopOut), in operating system + pixels. Pass NULL to not receive any parameter. + } + PROCEDURE XPLMGetWindowGeometryOS( + inWindowID : XPLMWindowID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowGeometryOS + + This routine allows you to set the position and size, in operating system + pixel coordinates, of a popped out window (that is, a window whose + positioning mode is xplm_WindowPopOut, which exists outside the X-Plane + simulation window, in its own first-class operating system window). + + Note that you are responsible for ensuring both that your window is popped + out (using XPLMWindowIsPoppedOut()) and that a monitor really exists at the + OS coordinates you provide (using XPLMGetAllMonitorBoundsOS()). + } + PROCEDURE XPLMSetWindowGeometryOS( + inWindowID : XPLMWindowID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMGetWindowGeometryVR + + Returns the width and height, in boxels, of a window in VR. Note that you + are responsible for ensuring your window is in VR (using + XPLMWindowIsInVR()). + } + PROCEDURE XPLMGetWindowGeometryVR( + inWindowID : XPLMWindowID; + outWidthBoxels : PInteger; { Can be nil } + outHeightBoxels : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + +{$IFDEF XPLM301} + { + XPLMSetWindowGeometryVR + + This routine allows you to set the size, in boxels, of a window in VR (that + is, a window whose positioning mode is xplm_WindowVR). + + Note that you are responsible for ensuring your window is in VR (using + XPLMWindowIsInVR()). + } + PROCEDURE XPLMSetWindowGeometryVR( + inWindowID : XPLMWindowID; + widthBoxels : Integer; + heightBoxels : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + + { + XPLMGetWindowIsVisible + + Returns true (1) if the specified window is visible. + } + FUNCTION XPLMGetWindowIsVisible( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetWindowIsVisible + + This routine shows or hides a window. + } + PROCEDURE XPLMSetWindowIsVisible( + inWindowID : XPLMWindowID; + inIsVisible : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMWindowIsPoppedOut + + True if this window has been popped out (making it a first-class window in + the operating system), which in turn is true if and only if you have set + the window's positioning mode to xplm_WindowPopOut. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK cannot be popped out.) + } + FUNCTION XPLMWindowIsPoppedOut( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMWindowIsInVR + + True if this window has been moved to the virtual reality (VR) headset, + which in turn is true if and only if you have set the window's positioning + mode to xplm_WindowVR. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM301 version of + the SDK cannot be moved to VR.) + } + FUNCTION XPLMWindowIsInVR( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + +{$IFDEF XPLM300} + { + XPLMSetWindowGravity + + A window's "gravity" controls how the window shifts as the whole X-Plane + window resizes. A gravity of 1 means the window maintains its positioning + relative to the right or top edges, 0 the left/bottom, and 0.5 keeps it + centered. + + Default gravity is (0, 1, 0, 1), meaning your window will maintain its + position relative to the top left and will not change size as its + containing window grows. + + If you wanted, say, a window that sticks to the top of the screen (with a + constant height), but which grows to take the full width of the window, you + would pass (0, 1, 1, 1). Because your left and right edges would maintain + their positioning relative to their respective edges of the screen, the + whole width of your window would change with the X-Plane window. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will simply get the default gravity.) + } + PROCEDURE XPLMSetWindowGravity( + inWindowID : XPLMWindowID; + inLeftGravity : Single; + inTopGravity : Single; + inRightGravity : Single; + inBottomGravity : Single); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowResizingLimits + + Sets the minimum and maximum size of the client rectangle of the given + window. (That is, it does not include any window styling that you might + have asked X-Plane to apply on your behalf.) All resizing operations are + constrained to these sizes. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will have no minimum or maximum size.) + } + PROCEDURE XPLMSetWindowResizingLimits( + inWindowID : XPLMWindowID; + inMinWidthBoxels : Integer; + inMinHeightBoxels : Integer; + inMaxWidthBoxels : Integer; + inMaxHeightBoxels : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMWindowPositioningMode + + XPLMWindowPositionMode describes how X-Plane will position your window on + the user's screen. X-Plane will maintain this positioning mode even as the + user resizes their window or adds/removes full-screen monitors. + + Positioning mode can only be set for "modern" windows (that is, windows + created using XPLMCreateWindowEx() and compiled against the XPLM300 SDK). + Windows created using the deprecated XPLMCreateWindow(), or windows + compiled against a pre-XPLM300 version of the SDK will simply get the + "free" positioning mode. + } +TYPE + XPLMWindowPositioningMode = ( + { The default positioning mode. Set the window geometry and its future } + { position will be determined by its window gravity, resizing limits, and } + { user interactions. } + xplm_WindowPositionFree = 0 + + { Keep the window centered on the monitor you specify } + ,xplm_WindowCenterOnMonitor = 1 + + { Keep the window full screen on the monitor you specify } + ,xplm_WindowFullScreenOnMonitor = 2 + + { Like gui_window_full_screen_on_monitor, but stretches over *all* monitors } + { and popout windows. This is an obscure one... unless you have a very good } + { reason to need it, you probably don't! } + ,xplm_WindowFullScreenOnAllMonitors = 3 + + { A first-class window in the operating system, completely separate from the } + { X-Plane window(s) } + ,xplm_WindowPopOut = 4 + +{$IFDEF XPLM301} + { A floating window visible on the VR headset } + ,xplm_WindowVR = 5 +{$ENDIF XPLM301} + + ); + PXPLMWindowPositioningMode = ^XPLMWindowPositioningMode; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowPositioningMode + + Sets the policy for how X-Plane will position your window. + + Some positioning modes apply to a particular monitor. For those modes, you + can pass a negative monitor index to position the window on the main + X-Plane monitor (the screen with the X-Plane menu bar at the top). Or, if + you have a specific monitor you want to position your window on, you can + pass a real monitor index as received from, e.g., + XPLMGetAllMonitorBoundsOS(). + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will always use xplm_WindowPositionFree.) + } + PROCEDURE XPLMSetWindowPositioningMode( + inWindowID : XPLMWindowID; + inPositioningMode : XPLMWindowPositioningMode; + inMonitorIndex : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowTitle + + Sets the name for a window. This only applies to windows that opted-in to + styling as an X-Plane 11 floating window (i.e., with styling mode + xplm_WindowDecorationRoundRectangle) when they were created using + XPLMCreateWindowEx(). + } + PROCEDURE XPLMSetWindowTitle( + inWindowID : XPLMWindowID; + inWindowTitle : XPLMString); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetWindowRefCon + + Returns a window's reference constant, the unique value you can use for + your own purposes. + } + FUNCTION XPLMGetWindowRefCon( + inWindowID : XPLMWindowID) : pointer; + cdecl; external XPLM_DLL; + + { + XPLMSetWindowRefCon + + Sets a window's reference constant. Use this to pass data to yourself in + the callbacks. + } + PROCEDURE XPLMSetWindowRefCon( + inWindowID : XPLMWindowID; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMTakeKeyboardFocus + + This routine gives a specific window keyboard focus. Keystrokes will be + sent to that window. Pass a window ID of 0 to remove keyboard focus from + any plugin-created windows and instead pass keyboard strokes directly to + X-Plane. + } + PROCEDURE XPLMTakeKeyboardFocus( + inWindow : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMHasKeyboardFocus + + Returns true (1) if the indicated window has keyboard focus. Pass a window + ID of 0 to see if no plugin window has focus, and all keystrokes will go + directly to X-Plane. + } + FUNCTION XPLMHasKeyboardFocus( + inWindow : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMBringWindowToFront + + This routine brings the window to the front of the Z-order for its layer. + Windows are brought to the front automatically when they are created. + Beyond that, you should make sure you are front before handling mouse + clicks. + + Note that this only brings your window to the front of its layer + (XPLMWindowLayer). Thus, if you have a window in the floating window layer + (xplm_WindowLayerFloatingWindows), but there is a modal window (in layer + xplm_WindowLayerModal) above you, you would still not be the true frontmost + window after calling this. (After all, the window layers are strictly + ordered, and no window in a lower layer can ever be above any window in a + higher one.) + } + PROCEDURE XPLMBringWindowToFront( + inWindow : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMIsWindowInFront + + This routine returns true if the window you passed in is the frontmost + visible window in its layer (XPLMWindowLayer). + + Thus, if you have a window at the front of the floating window layer + (xplm_WindowLayerFloatingWindows), this will return true even if there is a + modal window (in layer xplm_WindowLayerModal) above you. (Not to worry, + though: in such a case, X-Plane will not pass clicks or keyboard input down + to your layer until the window above stops "eating" the input.) + + Note that legacy windows are always placed in layer + xplm_WindowLayerFlightOverlay, while modern-style windows default to + xplm_WindowLayerFloatingWindows. This means it's perfectly consistent to + have two different plugin-created windows (one legacy, one modern) *both* + be in the front (of their different layers!) at the same time. + } + FUNCTION XPLMIsWindowInFront( + inWindow : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * KEY SNIFFERS + ___________________________________________________________________________} +{ + Low-level keyboard handlers. Allows for intercepting keystrokes outside the + normal rules of the user interface. +} + + + { + XPLMKeySniffer_f + + This is the prototype for a low level key-sniffing function. Window-based + UI _should not use this_! The windowing system provides high-level + mediated keyboard access, via the callbacks you attach to your + XPLMCreateWindow_t. By comparison, the key sniffer provides low level + keyboard access. + + Key sniffers are provided to allow libraries to provide non-windowed user + interaction. For example, the MUI library uses a key sniffer to do pop-up + text entry. + + Return 1 to pass the key on to the next sniffer, the window manager, + X-Plane, or whomever is down stream. Return 0 to consume the key. + + Warning: this API declares virtual keys as a signed character; however the + VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + to an unsigned char to get correct comparisons in C. + } +TYPE + XPLMKeySniffer_f = FUNCTION( + inChar : XPLMChar; + inFlags : XPLMKeyFlags; + inVirtualKey : XPLMChar; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMRegisterKeySniffer + + This routine registers a key sniffing callback. You specify whether you + want to sniff before the window system, or only sniff keys the window + system does not consume. You should ALMOST ALWAYS sniff non-control keys + after the window system. When the window system consumes a key, it is + because the user has "focused" a window. Consuming the key or taking + action based on the key will produce very weird results. Returns + 1 if successful. + } + FUNCTION XPLMRegisterKeySniffer( + inCallback : XPLMKeySniffer_f; + inBeforeWindows : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterKeySniffer + + This routine unregisters a key sniffer. You must unregister a key sniffer + for every time you register one with the exact same signature. Returns 1 + if successful. + } + FUNCTION XPLMUnregisterKeySniffer( + inCallback : XPLMKeySniffer_f; + inBeforeWindows : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * HOT KEYS + ___________________________________________________________________________} +{ + Keystrokes that can be managed by others. These are lower-level than window + keyboard handlers (i.e., callbacks you attach to your XPLMCreateWindow_t), + but higher level than key sniffers. +} + + + { + XPLMHotKey_f + + Your hot key callback simply takes a pointer of your choosing. + } +TYPE + XPLMHotKey_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMHotKeyID + + An opaque ID used to identify a hot key. + } + XPLMHotKeyID = pointer; + PXPLMHotKeyID = ^XPLMHotKeyID; + + { + XPLMRegisterHotKey + + This routine registers a hot key. You specify your preferred key stroke + virtual key/flag combination, a description of what your callback does (so + other plug-ins can describe the plug-in to the user for remapping) and a + callback function and opaque pointer to pass in). A new hot key ID is + returned. During execution, the actual key associated with your hot key + may change, but you are insulated from this. + } + FUNCTION XPLMRegisterHotKey( + inVirtualKey : XPLMChar; + inFlags : XPLMKeyFlags; + inDescription : XPLMString; + inCallback : XPLMHotKey_f; + inRefcon : pointer) : XPLMHotKeyID; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterHotKey + + Unregisters a hot key. You can only unregister your own hot keys. + } + PROCEDURE XPLMUnregisterHotKey( + inHotKey : XPLMHotKeyID); + cdecl; external XPLM_DLL; + + { + XPLMCountHotKeys + + Returns the number of current hot keys. + } + FUNCTION XPLMCountHotKeys: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetNthHotKey + + Returns a hot key by index, for iteration on all hot keys. + } + FUNCTION XPLMGetNthHotKey( + inIndex : Integer) : XPLMHotKeyID; + cdecl; external XPLM_DLL; + + { + XPLMGetHotKeyInfo + + Returns information about the hot key. Return NULL for any parameter you + don't want info about. The description should be at least 512 chars long. + } + PROCEDURE XPLMGetHotKeyInfo( + inHotKey : XPLMHotKeyID; + outVirtualKey : XPLMString; { Can be nil } + outFlags : PXPLMKeyFlags; { Can be nil } + outDescription : XPLMString; { Can be nil } + outPlugin : PXPLMPluginID); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetHotKeyCombination + + Remaps a hot key's keystrokes. You may remap another plugin's keystrokes. + } + PROCEDURE XPLMSetHotKeyCombination( + inHotKey : XPLMHotKeyID; + inVirtualKey : XPLMChar; + inFlags : XPLMKeyFlags); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMGraphics.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMGraphics.pas new file mode 100644 index 0000000..20ff61a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMGraphics.pas @@ -0,0 +1,424 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMGraphics; +INTERFACE +{ + A few notes on coordinate systems: + + X-Plane uses three kinds of coordinates. Global coordinates are specified + as latitude, longitude and elevation. This coordinate system never changes + but is not very precise. + + OpenGL (or 'local') coordinates are cartesian and shift with the plane. + They offer more precision and are used for 3-d OpenGL drawing. The X axis + is aligned east-west with positive X meaning east. The Y axis is aligned + straight up and down at the point 0,0,0 (but since the earth is round it is + not truly straight up and down at other points). The Z axis is aligned + north-south at 0, 0, 0 with positive Z pointing south (but since the earth + is round it isn't exactly north-south as you move east or west of 0, 0, 0). + One unit is one meter and the point 0,0,0 is on the surface of the earth at + sea level for some latitude and longitude picked by the sim such that the + user's aircraft is reasonably nearby. + + 2-d Panel coordinates are 2d, with the X axis horizontal and the Y axis + vertical. The point 0,0 is the bottom left and 1024,768 is the upper + right of the screen. This is true no matter what resolution the user's + monitor is in; when running in higher resolution, graphics will be + scaled. + + Use X-Plane's routines to convert between global and local coordinates. Do + not attempt to do this conversion yourself; the precise 'roundness' of + X-Plane's physics model may not match your own, and (to make things + weirder) the user can potentially customize the physics of the current + planet. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * X-PLANE GRAPHICS + ___________________________________________________________________________} +{ + These routines allow you to use OpenGL with X-Plane. +} + + + { + XPLMTextureID + + XPLM Texture IDs name well-known textures in the sim for you to use. This + allows you to recycle textures from X-Plane, saving VRAM. + + *Warning*: do not use these enums. The only remaining use they have is to + access the legacy compatibility v10 UI texture; if you need this, get it + via the Widgets library. + } +TYPE + XPLMTextureID = ( + { The bitmap that contains window outlines, button outlines, fonts, etc. } + xplm_Tex_GeneralInterface = 0 + +{$IFDEF XPLM_DEPRECATED} + { The exterior paint for the user's aircraft (daytime). } + ,xplm_Tex_AircraftPaint = 1 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { The exterior light map for the user's aircraft. } + ,xplm_Tex_AircraftLiteMap = 2 +{$ENDIF XPLM_DEPRECATED} + + ); + PXPLMTextureID = ^XPLMTextureID; + + { + XPLMSetGraphicsState + + XPLMSetGraphicsState changes OpenGL's fixed function pipeline state. You + are not responsible for restoring any state that is accessed via + XPLMSetGraphicsState, but you are responsible for not accessing this state + directly. + + - inEnableFog - enables or disables fog, equivalent to: glEnable(GL_FOG); + - inNumberTexUnits - enables or disables a number of multitexturing units. + If the number is 0, 2d texturing is disabled entirely, as in + glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a + number of multitexturing units are enabled sequentially, starting with + unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB); glEnable + (GL_TEXTURE_2D); + - inEnableLighting - enables or disables OpenGL lighting, e.g. + glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + - inEnableAlphaTesting - enables or disables the alpha test per pixel, e.g. + glEnable(GL_ALPHA_TEST); + - inEnableAlphaBlending - enables or disables alpha blending per pixel, + e.g. glEnable(GL_BLEND); + - inEnableDepthTesting - enables per pixel depth testing, as in + glEnable(GL_DEPTH_TEST); + - inEnableDepthWriting - enables writing back of depth information to the + depth bufffer, as in glDepthMask(GL_TRUE); + + The purpose of this function is to change OpenGL state while keeping + X-Plane aware of the state changes; this keeps X-Plane from getting + surprised by OGL state changes, and prevents X-Plane and plug-ins from + having to set all state before all draws; XPLMSetGraphicsState internally + skips calls to change state that is already properly enabled. + + X-Plane does not have a 'default' OGL state for plug-ins with respect to + the above state vector; plug-ins should totally set OGL state using this + API before drawing. Use XPLMSetGraphicsState instead of any of the above + OpenGL calls. + + WARNING: Any routine that performs drawing (e.g. XPLMDrawString or widget + code) may change X-Plane's state. Always set state before drawing after + unknown code has executed. + + *Deprecation Warnings*: X-Plane's lighting and fog environemnt is + significantly more complex than the fixed function pipeline can express; + do not assume that lighting and fog state is a good approximation for 3-d + drawing. Prefer to use XPLMInstancing to draw objects. All calls to + XPLMSetGraphicsState should have no fog or lighting. + } + PROCEDURE XPLMSetGraphicsState( + inEnableFog : Integer; + inNumberTexUnits : Integer; + inEnableLighting : Integer; + inEnableAlphaTesting: Integer; + inEnableAlphaBlending: Integer; + inEnableDepthTesting: Integer; + inEnableDepthWriting: Integer); + cdecl; external XPLM_DLL; + + { + XPLMBindTexture2d + + XPLMBindTexture2d changes what texture is bound to the 2d texturing + target. This routine caches the current 2d texture across all texturing + units in the sim and plug-ins, preventing extraneous binding. For + example, consider several plug-ins running in series; if they all use the + 'general interface' bitmap to do UI, calling this function will skip the + rebinding of the general interface texture on all but the first plug-in, + which can provide better frame rate son some graphics cards. + + inTextureID is the ID of the texture object to bind; inTextureUnit is a + zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 + units. (This number may increase in future versions of X-Plane.) + + Use this routine instead of glBindTexture(GL_TEXTURE_2D, ....); + } + PROCEDURE XPLMBindTexture2d( + inTextureNum : Integer; + inTextureUnit : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGenerateTextureNumbers + + Use this routine instead of glGenTextures to generate new texture object + IDs. This routine historically ensured that plugins don't use texure IDs + that X-Plane is reserving for its own use. + } + PROCEDURE XPLMGenerateTextureNumbers( + outTextureIDs : PInteger; + inCount : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM_DEPRECATED} + { + XPLMGetTexture + + XPLMGetTexture returns the OpenGL texture ID of an X-Plane texture based on + a generic identifying code. For example, you can get the texture for + X-Plane's UI bitmaps. + } + FUNCTION XPLMGetTexture( + inTexture : XPLMTextureID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + { + XPLMWorldToLocal + + This routine translates coordinates from latitude, longitude, and altitude + to local scene coordinates. Latitude and longitude are in decimal degrees, + and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + meters in the local OpenGL coordinate system. + } + PROCEDURE XPLMWorldToLocal( + inLatitude : Real; + inLongitude : Real; + inAltitude : Real; + outX : PReal; + outY : PReal; + outZ : PReal); + cdecl; external XPLM_DLL; + + { + XPLMLocalToWorld + + This routine translates a local coordinate triplet back into latitude, + longitude, and altitude. Latitude and longitude are in decimal degrees, + and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + meters in the local OpenGL coordinate system. + + NOTE: world coordinates are less precise than local coordinates; you should + try to avoid round tripping from local to world and back. + } + PROCEDURE XPLMLocalToWorld( + inX : Real; + inY : Real; + inZ : Real; + outLatitude : PReal; + outLongitude : PReal; + outAltitude : PReal); + cdecl; external XPLM_DLL; + + { + XPLMDrawTranslucentDarkBox + + This routine draws a translucent dark box, partially obscuring parts of the + screen but making text easy to read. This is the same graphics primitive + used by X-Plane to show text files and ATC info. + } + PROCEDURE XPLMDrawTranslucentDarkBox( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * X-PLANE TEXT + ___________________________________________________________________________} + + { + XPLMFontID + + X-Plane features some fixed-character fonts. Each font may have its own + metrics. + + WARNING: Some of these fonts are no longer supported or may have changed + geometries. For maximum copmatibility, see the comments below. + + Note: X-Plane 7 supports proportional-spaced fonts. Since no measuring + routine is available yet, the SDK will normally draw using a fixed-width + font. You can use a dataref to enable proportional font drawing on XP7 if + you want to. + } +TYPE + XPLMFontID = ( + { Mono-spaced font for user interface. Available in all versions of the SDK.} + xplmFont_Basic = 0 + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Menus = 1 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Metal = 2 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Led = 3 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_LedWide = 4 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelHUD = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelEFIS = 6 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelGPS = 7 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosGA = 8 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosBC = 9 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosHM = 10 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosGANarrow = 11 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosBCNarrow = 12 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosHMNarrow = 13 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Timer = 14 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_FullRound = 15 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_SmallRound = 16 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Menus_Localized = 17 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM200} + { Proportional UI font. } + ,xplmFont_Proportional = 18 +{$ENDIF XPLM200} + + ); + PXPLMFontID = ^XPLMFontID; + + { + XPLMDrawString + + This routine draws a NULL termianted string in a given font. Pass in the + lower left pixel that the character is to be drawn onto. Also pass the + character and font ID. This function returns the x offset plus the width of + all drawn characters. The color to draw in is specified as a pointer to an + array of three floating point colors, representing RGB intensities from 0.0 + to 1.0. + } + PROCEDURE XPLMDrawString( + inColorRGB : PSingle; + inXOffset : Integer; + inYOffset : Integer; + inChar : XPLMString; + inWordWrapWidth : PInteger; { Can be nil } + inFontID : XPLMFontID); + cdecl; external XPLM_DLL; + + { + XPLMDrawNumber + + This routine draws a number similar to the digit editing fields in + PlaneMaker and data output display in X-Plane. Pass in a color, a + position, a floating point value, and formatting info. Specify how many + integer and how many decimal digits to show and whether to show a sign, as + well as a character set. This routine returns the xOffset plus width of the + string drawn. + } + PROCEDURE XPLMDrawNumber( + inColorRGB : PSingle; + inXOffset : Integer; + inYOffset : Integer; + inValue : Real; + inDigits : Integer; + inDecimals : Integer; + inShowSign : Integer; + inFontID : XPLMFontID); + cdecl; external XPLM_DLL; + + { + XPLMGetFontDimensions + + This routine returns the width and height of a character in a given font. + It also tells you if the font only supports numeric digits. Pass NULL if + you don't need a given field. Note that for a proportional font the width + will be an arbitrary, hopefully average width. + } + PROCEDURE XPLMGetFontDimensions( + inFontID : XPLMFontID; + outCharWidth : PInteger; { Can be nil } + outCharHeight : PInteger; { Can be nil } + outDigitsOnly : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMMeasureString + + This routine returns the width in pixels of a string using a given font. + The string is passed as a pointer plus length (and does not need to be null + terminated); this is used to allow for measuring substrings. The return + value is floating point; it is possible that future font drawing may allow + for fractional pixels. + } + FUNCTION XPLMMeasureString( + inFontID : XPLMFontID; + inChar : XPLMString; + inNumChars : Integer) : Single; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMInstance.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMInstance.pas new file mode 100644 index 0000000..a38d2bb --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMInstance.pas @@ -0,0 +1,125 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMInstance; +INTERFACE +{ + This API provides instanced drawing of X-Plane objects (.obj files). In + contrast to old drawing APIs, which required you to draw your own objects + per-frame, the instancing API allows you to simply register an OBJ for + drawing, then move or manipulate it later (as needed). + + This provides one tremendous benefit: it keeps all dataref operations for + your object in one place. Because datarefs are main thread only, allowing + dataref access anywhere is a serious performance bottleneck for the + simulator---the whole simulator has to pause and wait for each dataref + access. This performance penalty will only grow worse as X-Plane moves + toward an ever more heavily multithreaded engine. + + The instancing API allows X-Plane to isolate all dataref manipulations for + all plugin object drawing to one place, potentially providing huge + performance gains. + + Here's how it works: + + When an instance is created, it provides a list of all datarefs you want to + manipulate in for the OBJ in the future. This list of datarefs replaces the + ad-hoc collections of dataref objects previously used by art assets. Then, + per-frame, you can manipulate the instance by passing in a "block" of + packed floats representing the current values of the datarefs for your + instance. (Note that the ordering of this set of packed floats must exactly + match the ordering of the datarefs when you created your instance.) +} + +USES + XPLMDefs, XPLMScenery; + {$A4} +{___________________________________________________________________________ + * Instance Creation and Destruction + ___________________________________________________________________________} +{ + Registers and unregisters instances. +} + + +TYPE + { + XPLMInstanceRef + + An opaque handle to an instance. + } + XPLMInstanceRef = pointer; + PXPLMInstanceRef = ^XPLMInstanceRef; + + { + XPLMCreateInstance + + XPLMCreateInstance creates a new instance, managed by your plug-in, and + returns a handle to the instance. A few important requirements: + + * The object passed in must be fully loaded and returned from the XPLM + before you can create your instance; you cannot pass a null obj ref, nor + can you change the ref later. + + * If you use any custom datarefs in your object, they must be registered + before the object is loaded. This is true even if their data will be + provided via the instance dataref list. + + * The instance dataref array must be a valid ptr to an array of at least + one item that is null terminated. That is, if you do not want any + datarefs, you must passa ptr to an array with a null item. You cannot + pass null for this. + } + FUNCTION XPLMCreateInstance( + obj : XPLMObjectRef; + datarefs : PXPLMString) : XPLMInstanceRef; + cdecl; external XPLM_DLL; + + { + XPLMDestroyInstance + + XPLMDestroyInstance destroys and deallocates your instance; once called, + you are still responsible for releasing the OBJ ref. + + Tip: you can release your OBJ ref after you call XPLMCreateInstance as long + as you never use it again; the instance will maintain its own reference to + the OBJ and the object OBJ be deallocated when the instance is destroyed. + } + PROCEDURE XPLMDestroyInstance( + instance : XPLMInstanceRef); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * Instance Manipulation + ___________________________________________________________________________} + + { + XPLMInstanceSetPosition + + Updates both the position of the instance and all datarefs you registered + for it. Call this from a flight loop callback or UI callback. + + __DO NOT__ call XPLMInstanceSetPosition from a drawing callback; the whole + point of instancing is that you do not need any drawing callbacks. Setting + instance data from a drawing callback may have undefined consequences, and + the drawing callback hurts FPS unnecessarily. + + The memory pointed to by the data pointer must be large enough to hold one + float for every data ref you have registered, and must contain valid + floating point data. + + BUG: before X-Plane 11.50, if you have no dataref registered, you must + still pass a valid pointer for data and not null. + } + PROCEDURE XPLMInstanceSetPosition( + instance : XPLMInstanceRef; + new_position : PXPLMDrawInfo_t; + data : PSingle); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMMap.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMMap.pas new file mode 100644 index 0000000..61c82dc --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMMap.pas @@ -0,0 +1,611 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMMap; +INTERFACE +{ + This API allows you to create new layers within X-Plane maps. Your layers + can draw arbitrary OpenGL, but they conveniently also have access to + X-Plane's built-in icon and label drawing functions. + + As of X-Plane 11, map drawing happens in three stages: + + 1. backgrounds and "fill," + 2. icons, and + 3. labels. + + Thus, all background drawing gets layered beneath all icons, which likewise + get layered beneath all labels. Within each stage, the map obeys a + consistent layer ordering, such that "fill" layers (layers that cover a + large amount of map area, like the terrain and clouds) appear beneath + "markings" layers (like airport icons). This ensures that layers with fine + details don't get obscured by layers with larger details. + + The XPLM map API reflects both aspects of this draw layering: you can + register a layer as providing either markings or fill, and X-Plane will + draw your fill layers beneath your markings layers (regardless of + registration order). Likewise, you are guaranteed that your layer's icons + (added from within an icon callback) will go above your layer's OpenGL + drawing, and your labels will go above your icons. + + The XPLM guarantees that all plugin-created fill layers go on top of all + native X-Plane fill layers, and all plugin-created markings layers go on + top of all X-Plane markings layers (with the exception of the aircraft + icons). It also guarantees that the draw order of your own plugin's layers + will be consistent. But, for layers created by different plugins, the only + guarantee is that we will draw all of one plugin's layers of each type + (fill, then markings), then all of the others'; we don't guarantee which + plugin's fill and markings layers go on top of the other's. + + As of X-Plane 11, maps use true cartographic projections for their drawing, + and different maps may use different projections. For that reason, all + drawing calls include an opaque handle for the projection you should use to + do the drawing. Any time you would draw at a particular latitude/longitude, + you'll need to ask the projection to translate that position into "map + coordinates." (Note that the projection is guaranteed not to change between + calls to your prepare-cache hook, so if you cache your map coordinates + ahead of time, there's no need to re-project them when you actually draw.) + + In addition to mapping normal latitude/longitude locations into map + coordinates, the projection APIs also let you know the current heading for + north. (Since X-Plane 11 maps can rotate to match the heading of the user's + aircraft, it's not safe to assume that north is at zero degrees rotation.) +} + +USES + XPLMDefs; + {$A4} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * DRAWING CALLBACKS + ___________________________________________________________________________} +{ + When you create a new map layer (using XPLMCreateMapLayer), you can provide + any or all of these callbacks. They allow you to insert your own OpenGL + drawing, text labels, and icons into the X-Plane map at the appropriate + places, allowing your layer to behave as similarly to X-Plane's built-in + layers as possible. +} + + +TYPE + { + XPLMMapLayerID + + This is an opaque handle for a plugin-created map layer. Pass it to the map + drawing APIs from an appropriate callback to draw in the layer you created. + } + XPLMMapLayerID = pointer; + PXPLMMapLayerID = ^XPLMMapLayerID; + + { + XPLMMapProjectionID + + This is an opaque handle for a map projection. Pass it to the projection + APIs to translate between map coordinates and latitude/longitudes. + } + XPLMMapProjectionID = pointer; + PXPLMMapProjectionID = ^XPLMMapProjectionID; + + { + XPLMMapStyle + + Indicates the visual style being drawn by the map. In X-Plane, the user can + choose between a number of map types, and different map types may have use + a different visual representation for the same elements (for instance, the + visual style of the terrain layer changes drastically between the VFR and + IFR layers), or certain layers may be disabled entirely in some map types + (e.g., localizers are only visible in the IFR low-enroute style). + } + XPLMMapStyle = ( + xplm_MapStyle_VFR_Sectional = 0 + + ,xplm_MapStyle_IFR_LowEnroute = 1 + + ,xplm_MapStyle_IFR_HighEnroute = 2 + + ); + PXPLMMapStyle = ^XPLMMapStyle; + + { + XPLMMapDrawingCallback_f + + This is the OpenGL map drawing callback for plugin-created map layers. You + can perform arbitrary OpenGL drawing from this callback, with one + exception: changes to the Z-buffer are not permitted, and will result in + map drawing errors. + + All drawing done from within this callback appears beneath all built-in + X-Plane icons and labels, but above the built-in "fill" layers (layers + providing major details, like terrain and water). Note, however, that the + relative ordering between the drawing callbacks of different plugins is not + guaranteed. + } + XPLMMapDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapIconDrawingCallback_f + + This is the icon drawing callback that enables plugin-created map layers to + draw icons using X-Plane's built-in icon drawing functionality. You can + request an arbitrary number of PNG icons to be drawn via + XPLMDrawMapIconFromSheet() from within this callback, but you may not + perform any OpenGL drawing here. + + Icons enqueued by this function will appear above all OpenGL drawing + (performed by your optional XPLMMapDrawingCallback_f), and above all + built-in X-Plane map icons of the same layer type ("fill" or "markings," as + determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + however, that the relative ordering between the drawing callbacks of + different plugins is not guaranteed. + } + XPLMMapIconDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapLabelDrawingCallback_f + + This is the label drawing callback that enables plugin-created map layers + to draw text labels using X-Plane's built-in labeling functionality. You + can request an arbitrary number of text labels to be drawn via + XPLMDrawMapLabel() from within this callback, but you may not perform any + OpenGL drawing here. + + Labels enqueued by this function will appear above all OpenGL drawing + (performed by your optional XPLMMapDrawingCallback_f), and above all + built-in map icons and labels of the same layer type ("fill" or "markings," + as determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + however, that the relative ordering between the drawing callbacks of + different plugins is not guaranteed. + } + XPLMMapLabelDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * LAYER MANAGEMENT CALLBACKS + ___________________________________________________________________________} +{ + These are various "bookkeeping" callbacks that your map layer can receive + (if you provide the callback in your XPLMCreateMapLayer_t). They allow you + to manage the lifecycle of your layer, as well as cache any + computationally-intensive preparation you might need for drawing. +} + + + { + XPLMMapPrepareCacheCallback_f + + A callback used to allow you to cache whatever information your layer needs + to draw in the current map area. + + This is called each time the map's total bounds change. This is typically + triggered by new DSFs being loaded, such that X-Plane discards old, + now-distant DSFs and pulls in new ones. At that point, the available bounds + of the map also change to match the new DSF area. + + By caching just the information you need to draw in this area, your future + draw calls can be made faster, since you'll be able to simply "splat" your + precomputed information each frame. + + We guarantee that the map projection will not change between successive + prepare cache calls, nor will any draw call give you bounds outside these + total map bounds. So, if you cache the projected map coordinates of all the + items you might want to draw in the total map area, you can be guaranteed + that no draw call will be asked to do any new work. + } +TYPE + XPLMMapPrepareCacheCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inTotalMapBoundsLeftTopRightBottom: PSingle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapWillBeDeletedCallback_f + + Called just before your map layer gets deleted. Because SDK-created map + layers have the same lifetime as the X-Plane map that contains them, if the + map gets unloaded from memory, your layer will too. + } + XPLMMapWillBeDeletedCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inRefcon : pointer); cdecl; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP LAYER CREATION AND DESTRUCTION + ___________________________________________________________________________} +{ + Enables the creation of new map layers. Layers are created for a particular + instance of the X-Plane map. For instance, if you want your layer to appear + in both the normal map interface and the Instructor Operator Station (IOS), + you would need two separate calls to XPLMCreateMapLayer(), with two + different values for your XPLMCreateMapLayer_t::layer_name. + + Your layer's lifetime will be determined by the lifetime of the map it is + created in. If the map is destroyed (on the X-Plane side), your layer will + be too, and you'll receive a callback to your + XPLMMapWillBeDeletedCallback_f. +} + + + { + XPLMMapLayerType + + Indicates the type of map layer you are creating. Fill layers will always + be drawn beneath markings layers. + } +TYPE + XPLMMapLayerType = ( + { A layer that draws "fill" graphics, like weather patterns, terrain, etc. } + { Fill layers frequently cover a large portion of the visible map area. } + xplm_MapLayer_Fill = 0 + + { A layer that provides markings for particular map features, like NAVAIDs, } + { airports, etc. Even dense markings layers cover a small portion of the } + { total map area. } + ,xplm_MapLayer_Markings = 1 + + ); + PXPLMMapLayerType = ^XPLMMapLayerType; + +CONST + { Globally unique identifier for X-Plane's Map window, used as the } + { mapToCreateLayerIn parameter in XPLMCreateMapLayer_t } + XPLM_MAP_USER_INTERFACE = "XPLM_MAP_USER_INTERFACE"; + + { Globally unique identifier for X-Plane's Instructor Operator Station } + { window, used as the mapToCreateLayerIn parameter in XPLMCreateMapLayer_t } + XPLM_MAP_IOS = "XPLM_MAP_IOS"; + + { + XPLMCreateMapLayer_t + + This structure defines all of the parameters used to create a map layer + using XPLMCreateMapLayer. The structure will be expanded in future SDK APIs + to include more features. Always set the structSize member to the size of + your struct in bytes! + + Each layer must be associated with exactly one map instance in X-Plane. + That map, and that map alone, will call your callbacks. Likewise, when that + map is deleted, your layer will be as well. + } +TYPE + XPLMCreateMapLayer_t = RECORD + { Used to inform XPLMCreateMapLayer() of the SDK version you compiled } + { against; should always be set to sizeof(XPLMCreateMapLayer_t) } + structSize : Integer; + { Globally unique string identifying the map you want this layer to appear } + { in. As of XPLM300, this is limited to one of XPLM_MAP_USER_INTERFACE or } + { XPLM_MAP_IOS } + mapToCreateLayerIn : XPLMString; + { The type of layer you are creating, used to determine draw order (all } + { plugin-created markings layers are drawn above all plugin-created fill } + { layers) } + layerType : XPLMMapLayerType; + { Optional callback to inform you this layer is being deleted (due to its } + { owning map being destroyed) } + willBeDeletedCallback : XPLMMapWillBeDeletedCallback_f; + { Optional callback you want to use to prepare your draw cache when the map } + { bounds change (set to NULL if you don't want this callback) } + prepCacheCallback : XPLMMapPrepareCacheCallback_f; + { Optional callback you want to use for arbitrary OpenGL drawing, which goes } + { beneath all icons in the map's layering system (set to NULL if you don't } + { want this callback) } + drawCallback : XPLMMapDrawingCallback_f; + { Optional callback you want to use for drawing icons, which go above all } + { built-in X-Plane icons (except the aircraft) in the map's layering system } + { (set to NULL if you don't want this callback) } + iconCallback : XPLMMapIconDrawingCallback_f; + { Optional callback you want to use for drawing map labels, which go above } + { all built-in X-Plane icons and labels (except those of aircraft) in the } + { map's layering system (set to NULL if you don't want this callback) } + labelCallback : XPLMMapLabelDrawingCallback_f; + { True if you want a checkbox to be created in the map UI to toggle this } + { layer on and off; false if the layer should simply always be enabled } + showUiToggle : Integer; + { Short label to use for this layer in the user interface } + layerName : XPLMString; + { A reference to arbitrary data that will be passed to your callbacks } + refcon : pointer; + END; + PXPLMCreateMapLayer_t = ^XPLMCreateMapLayer_t; + + { + XPLMCreateMapLayer + + This routine creates a new map layer. You pass in an XPLMCreateMapLayer_t + structure with all of the fields set in. You must set the structSize of + the structure to the size of the actual structure you used. + + Returns NULL if the layer creation failed. This happens most frequently + because the map you specified in your + XPLMCreateMapLayer_t::mapToCreateLayerIn field doesn't exist (that is, if + XPLMMapExists() returns 0 for the specified map). You can use + XPLMRegisterMapCreationHook() to get a notification each time a new map is + opened in X-Plane, at which time you can create layers in it. + } + FUNCTION XPLMCreateMapLayer( + inParams : PXPLMCreateMapLayer_t) : XPLMMapLayerID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyMapLayer + + Destroys a map layer you created (calling your + XPLMMapWillBeDeletedCallback_f if applicable). Returns true if a deletion + took place. + } + FUNCTION XPLMDestroyMapLayer( + inLayer : XPLMMapLayerID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMMapCreatedCallback_f + + A callback to notify your plugin that a new map has been created in + X-Plane. This is the best time to add a custom map layer using + XPLMCreateMapLayer(). + + No OpenGL drawing is permitted within this callback. + } +TYPE + XPLMMapCreatedCallback_f = PROCEDURE( + mapIdentifier : XPLMString; + refcon : pointer); cdecl; + + { + XPLMRegisterMapCreationHook + + Registers your callback to receive a notification each time a new map is + constructed in X-Plane. This callback is the best time to add your custom + map layer using XPLMCreateMapLayer(). + + Note that you will not be notified about any maps that already exist---you + can use XPLMMapExists() to check for maps that were created previously. + } + PROCEDURE XPLMRegisterMapCreationHook( + callback : XPLMMapCreatedCallback_f; + refcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMMapExists + + Returns 1 if the map with the specified identifier already exists in + X-Plane. In that case, you can safely call XPLMCreateMapLayer() specifying + that your layer should be added to that map. + } + FUNCTION XPLMMapExists( + mapIdentifier : XPLMString) : Integer; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP DRAWING + ___________________________________________________________________________} +{ + These APIs are only valid from within a map drawing callback (one of + XPLMIconDrawingCallback_t or XPLMMapLabelDrawingCallback_f). Your drawing + callbacks are registered when you create a new map layer as part of your + XPLMCreateMapLayer_t. The functions here hook into X-Plane's built-in map + drawing functionality for icons and labels, so that you get a consistent + style with the rest of the X-Plane map. + + Note that the X-Plane 11 map introduces a strict ordering: layers of type + xplm_MapLayer_Fill get drawn beneath all xplm_MapLayer_Markings layers. + Likewise, all OpenGL drawing (performed in your layer's + XPLMMapDrawingCallback_f) will appear beneath any icons and labels you + draw. +} + + + { + XPLMMapOrientation + + Indicates whether a map element should be match its rotation to the map + itself, or to the user interface. For instance, the map itself may be + rotated such that "up" matches the user's aircraft, but you may want to + draw a text label such that it is always rotated zero degrees relative to + the user's perspective. In that case, you would have it draw with UI + orientation. + } +TYPE + XPLMMapOrientation = ( + { Orient such that a 0 degree rotation matches the map's north } + xplm_MapOrientation_Map = 0 + + { Orient such that a 0 degree rotation is "up" relative to the user interface} + ,xplm_MapOrientation_UI = 1 + + ); + PXPLMMapOrientation = ^XPLMMapOrientation; + + { + XPLMDrawMapIconFromSheet + + Enables plugin-created map layers to draw PNG icons using X-Plane's + built-in icon drawing functionality. Only valid from within an + XPLMIconDrawingCallback_t (but you can request an arbitrary number of icons + to be drawn from within your callback). + + X-Plane will automatically manage the memory for your texture so that it + only has to be loaded from disk once as long as you continue drawing it + per-frame. (When you stop drawing it, the memory may purged in a "garbage + collection" pass, require a load from disk in the future.) + + Instead of having X-Plane draw a full PNG, this method allows you to use UV + coordinates to request a portion of the image to be drawn. This allows you + to use a single texture load (of an icon sheet, for example) to draw many + icons. Doing so is much more efficient than drawing a dozen different small + PNGs. + + The UV coordinates used here treat the texture you load as being comprised + of a number of identically sized "cells." You specify the width and height + in cells (ds and dt, respectively), as well as the coordinates within the + cell grid for the sub-image you'd like to draw. + + Note that you can use different ds and dt values in subsequent calls with + the same texture sheet. This enables you to use icons of different sizes in + the same sheet if you arrange them properly in the PNG. + + This function is only valid from within an XPLMIconDrawingCallback_t (but + you can request an arbitrary number of icons to be drawn from within your + callback). + } + PROCEDURE XPLMDrawMapIconFromSheet( + layer : XPLMMapLayerID; + inPngPath : XPLMString; + s : Integer; + t : Integer; + ds : Integer; + dt : Integer; + mapX : Single; + mapY : Single; + orientation : XPLMMapOrientation; + rotationDegrees : Single; + mapWidth : Single); + cdecl; external XPLM_DLL; + + { + XPLMDrawMapLabel + + Enables plugin-created map layers to draw text labels using X-Plane's + built-in labeling functionality. Only valid from within an + XPLMMapLabelDrawingCallback_f (but you can request an arbitrary number of + text labels to be drawn from within your callback). + } + PROCEDURE XPLMDrawMapLabel( + layer : XPLMMapLayerID; + inText : XPLMString; + mapX : Single; + mapY : Single; + orientation : XPLMMapOrientation; + rotationDegrees : Single); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP PROJECTIONS + ___________________________________________________________________________} +{ + As of X-Plane 11, the map draws using true cartographic projections, and + different maps may use different projections. Thus, to draw at a particular + latitude and longitude, you must first transform your real-world + coordinates into map coordinates. + + The map projection is also responsible for giving you the current scale of + the map. That is, the projection can tell you how many map units correspond + to 1 meter at a given point. + + Finally, the map projection can give you the current rotation of the map. + Since X-Plane 11 maps can rotate to match the heading of the aircraft, the + map's rotation can potentially change every frame. +} + + + { + XPLMMapProject + + Projects a latitude/longitude into map coordinates. This is the inverse of + XPLMMapUnproject(). + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + PROCEDURE XPLMMapProject( + projection : XPLMMapProjectionID; + latitude : Real; + longitude : Real; + outX : PSingle; + outY : PSingle); + cdecl; external XPLM_DLL; + + { + XPLMMapUnproject + + Transforms map coordinates back into a latitude and longitude. This is the + inverse of XPLMMapProject(). + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + PROCEDURE XPLMMapUnproject( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single; + outLatitude : PReal; + outLongitude : PReal); + cdecl; external XPLM_DLL; + + { + XPLMMapScaleMeter + + Returns the number of map units that correspond to a distance of one meter + at a given set of map coordinates. + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + FUNCTION XPLMMapScaleMeter( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single) : Single; + cdecl; external XPLM_DLL; + + { + XPLMMapGetNorthHeading + + Returns the heading (in degrees clockwise from "up") that corresponds to + north at a given point on the map. In other words, if your runway has a + true heading of 360, you would use "north" as the Cartesian angle at which + to draw the runway on the map. (You would add the result of + XPLMMapGetNorthHeading() to your true heading to get the map angle.) + + This is necessary becuase X-Plane's map can be rotated to match your + aircraft's orientation; north is not always "up." + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + FUNCTION XPLMMapGetNorthHeading( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single) : Single; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMMenus.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMMenus.pas new file mode 100644 index 0000000..754a434 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMMenus.pas @@ -0,0 +1,277 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMMenus; +INTERFACE +{ + Plug-ins can create menus in the menu bar of X-Plane. This is done by + creating a menu and then creating items. Menus are referred to by an + opaque ID. Items are referred to by (zero-based) index number. + + Menus are "sandboxed" between plugins---no plugin can access the menus of + any other plugin. Furthermore, all menu indices are relative to your + plugin's menus only; if your plugin creates two sub-menus in the Plugins + menu at different times, it doesn't matter how many other plugins also + create sub-menus of Plugins in the intervening time: your sub-menus will be + given menu indices 0 and 1. (The SDK does some work in the back-end to + filter out menus that are irrelevant to your plugin in order to deliver + this consistency for each plugin.) + + When you create a menu item, you specify how we should handle clicks on + that menu item. You can either have the XPLM trigger a callback (the + XPLMMenuHandler_f associated with the menu that contains the item), or you + can simply have a command be triggered (with no associated call to your + menu handler). The advantage of the latter method is that X-Plane will + display any keyboard shortcuts associated with the command. (In contrast, + there are no keyboard shortcuts associated with menu handler callbacks with + specific parameters.) + + Menu text in X-Plane is UTF8; X-Plane's character set covers latin, greek + and cyrillic characters, Katakana, as well as some Japanese symbols. Some + APIs have a inDeprecatedAndIgnored parameter that used to select a + character set; since X-Plane 9 all localization is done via UTF-8 only. +} + +USES + XPLMDefs, XPLMUtilities; + {$A4} +{___________________________________________________________________________ + * XPLM MENUS + ___________________________________________________________________________} + + { + XPLMMenuCheck + + These enumerations define the various 'check' states for an X-Plane menu. + 'checking' in X-Plane actually appears as a light which may or may not be + lit. So there are three possible states. + } +TYPE + XPLMMenuCheck = ( + { there is no symbol to the left of the menu item. } + xplm_Menu_NoCheck = 0 + + { the menu has a mark next to it that is unmarked (not lit). } + ,xplm_Menu_Unchecked = 1 + + { the menu has a mark next to it that is checked (lit). } + ,xplm_Menu_Checked = 2 + + ); + PXPLMMenuCheck = ^XPLMMenuCheck; + + { + XPLMMenuID + + This is a unique ID for each menu you create. + } + XPLMMenuID = pointer; + PXPLMMenuID = ^XPLMMenuID; + + { + XPLMMenuHandler_f + + A menu handler function takes two reference pointers, one for the menu + (specified when the menu was created) and one for the item (specified when + the item was created). + } + XPLMMenuHandler_f = PROCEDURE( + inMenuRef : pointer; + inItemRef : pointer); cdecl; + + { + XPLMFindPluginsMenu + + This function returns the ID of the plug-ins menu, which is created for you + at startup. + } + FUNCTION XPLMFindPluginsMenu: XPLMMenuID; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMFindAircraftMenu + + This function returns the ID of the menu for the currently-loaded aircraft, + used for showing aircraft-specific commands. + + The aircraft menu is created by X-Plane at startup, but it remains hidden + until it is populated via XPLMAppendMenuItem() or + XPLMAppendMenuItemWithCommand(). + + Only plugins loaded with the user's current aircraft are allowed to access + the aircraft menu. For all other plugins, this will return NULL, and any + attempts to add menu items to it will fail. + } + FUNCTION XPLMFindAircraftMenu: XPLMMenuID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMCreateMenu + + This function creates a new menu and returns its ID. It returns NULL if + the menu cannot be created. Pass in a parent menu ID and an item index to + create a submenu, or NULL for the parent menu to put the menu in the menu + bar. The menu's name is only used if the menu is in the menubar. You also + pass a handler function and a menu reference value. Pass NULL for the + handler if you do not need callbacks from the menu (for example, if it only + contains submenus). + + Important: you must pass a valid, non-empty menu title even if the menu is + a submenu where the title is not visible. + } + FUNCTION XPLMCreateMenu( + inName : XPLMString; + inParentMenu : XPLMMenuID; + inParentItem : Integer; + inHandler : XPLMMenuHandler_f; + inMenuRef : pointer) : XPLMMenuID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyMenu + + This function destroys a menu that you have created. Use this to remove a + submenu if necessary. (Normally this function will not be necessary.) + } + PROCEDURE XPLMDestroyMenu( + inMenuID : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMClearAllMenuItems + + This function removes all menu items from a menu, allowing you to rebuild + it. Use this function if you need to change the number of items on a menu. + } + PROCEDURE XPLMClearAllMenuItems( + inMenuID : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMAppendMenuItem + + This routine appends a new menu item to the bottom of a menu and returns + its index. Pass in the menu to add the item to, the items name, and a void + * ref for this item. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + + Note that all menu indices returned are relative to your plugin's menus + only; if your plugin creates two sub-menus in the Plugins menu at different + times, it doesn't matter how many other plugins also create sub-menus of + Plugins in the intervening time: your sub-menus will be given menu indices + 0 and 1. (The SDK does some work in the back-end to filter out menus that + are irrelevant to your plugin in order to deliver this consistency for each + plugin.) + } + FUNCTION XPLMAppendMenuItem( + inMenu : XPLMMenuID; + inItemName : XPLMString; + inItemRef : pointer; + inDeprecatedAndIgnored: Integer) : Integer; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMAppendMenuItemWithCommand + + Like XPLMAppendMenuItem(), but instead of the new menu item triggering the + XPLMMenuHandler_f of the containiner menu, it will simply execute the + command you pass in. Using a command for your menu item allows the user to + bind a keyboard shortcut to the command and see that shortcut represented + in the menu. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + + Like XPLMAppendMenuItem(), all menu indices are relative to your plugin's + menus only. + } + FUNCTION XPLMAppendMenuItemWithCommand( + inMenu : XPLMMenuID; + inItemName : XPLMString; + inCommandToExecute : XPLMCommandRef) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMAppendMenuSeparator + + This routine adds a separator to the end of a menu. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + } + PROCEDURE XPLMAppendMenuSeparator( + inMenu : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMSetMenuItemName + + This routine changes the name of an existing menu item. Pass in the menu + ID and the index of the menu item. + } + PROCEDURE XPLMSetMenuItemName( + inMenu : XPLMMenuID; + inIndex : Integer; + inItemName : XPLMString; + inDeprecatedAndIgnored: Integer); + cdecl; external XPLM_DLL; + + { + XPLMCheckMenuItem + + Set whether a menu item is checked. Pass in the menu ID and item index. + } + PROCEDURE XPLMCheckMenuItem( + inMenu : XPLMMenuID; + index : Integer; + inCheck : XPLMMenuCheck); + cdecl; external XPLM_DLL; + + { + XPLMCheckMenuItemState + + This routine returns whether a menu item is checked or not. A menu item's + check mark may be on or off, or a menu may not have an icon at all. + } + PROCEDURE XPLMCheckMenuItemState( + inMenu : XPLMMenuID; + index : Integer; + outCheck : PXPLMMenuCheck); + cdecl; external XPLM_DLL; + + { + XPLMEnableMenuItem + + Sets whether this menu item is enabled. Items start out enabled. + } + PROCEDURE XPLMEnableMenuItem( + inMenu : XPLMMenuID; + index : Integer; + enabled : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM210} + { + XPLMRemoveMenuItem + + Removes one item from a menu. Note that all menu items below are moved up + one; your plugin must track the change in index numbers. + } + PROCEDURE XPLMRemoveMenuItem( + inMenu : XPLMMenuID; + inIndex : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMNavigation.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMNavigation.pas new file mode 100644 index 0000000..044b99b --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMNavigation.pas @@ -0,0 +1,350 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMNavigation; +INTERFACE +{ + The XPLM Navigation APIs give you some access to the navigation databases + inside X-Plane. X-Plane stores all navigation information in RAM, so by + using these APIs you can gain access to most information without having to + go to disk or parse the files yourself. + + You can also use this API to program the FMS. You must use the navigation + APIs to find the nav-aids you want to program into the FMS, since the FMS + is powered internally by X-Plane's navigation database. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * NAVIGATION DATABASE ACCESS + ___________________________________________________________________________} + + { + XPLMNavType + + These enumerations define the different types of navaids. They are each + defined with a separate bit so that they may be bit-wise added together to + form sets of nav-aid types. + + NOTE: xplm_Nav_LatLon is a specific lat-lon coordinate entered into the + FMS. It will not exist in the database, and cannot be programmed into the + FMS. Querying the FMS for navaids will return it. Use + XPLMSetFMSEntryLatLon to set a lat/lon waypoint. + } +TYPE + XPLMNavType = ( + xplm_Nav_Unknown = 0 + + ,xplm_Nav_Airport = 1 + + ,xplm_Nav_NDB = 2 + + ,xplm_Nav_VOR = 4 + + ,xplm_Nav_ILS = 8 + + ,xplm_Nav_Localizer = 16 + + ,xplm_Nav_GlideSlope = 32 + + ,xplm_Nav_OuterMarker = 64 + + ,xplm_Nav_MiddleMarker = 128 + + ,xplm_Nav_InnerMarker = 256 + + ,xplm_Nav_Fix = 512 + + ,xplm_Nav_DME = 1024 + + ,xplm_Nav_LatLon = 2048 + + ); + PXPLMNavType = ^XPLMNavType; + + { + XPLMNavRef + + XPLMNavRef is an iterator into the navigation database. The navigation + database is essentially an array, but it is not necessarily densely + populated. The only assumption you can safely make is that like-typed + nav-aids are grouped together. + + Use XPLMNavRef to refer to a nav-aid. + + XPLM_NAV_NOT_FOUND is returned by functions that return an XPLMNavRef when + the iterator must be invalid. + } + XPLMNavRef = Integer; + PXPLMNavRef = ^XPLMNavRef; + +CONST + XPLM_NAV_NOT_FOUND = -1; + + { + XPLMGetFirstNavAid + + This returns the very first navaid in the database. Use this to traverse + the entire database. Returns XPLM_NAV_NOT_FOUND if the nav database is + empty. + } + FUNCTION XPLMGetFirstNavAid: XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMGetNextNavAid + + Given a valid nav aid ref, this routine returns the next navaid. It + returns XPLM_NAV_NOT_FOUND if the nav aid passed in was invalid or if the + navaid passed in was the last one in the database. Use this routine to + iterate across all like-typed navaids or the entire database. + } + FUNCTION XPLMGetNextNavAid( + inNavAidRef : XPLMNavRef) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindFirstNavAidOfType + + This routine returns the ref of the first navaid of the given type in the + database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + database. You must pass exactly one nav aid type to this routine. + } + FUNCTION XPLMFindFirstNavAidOfType( + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindLastNavAidOfType + + This routine returns the ref of the last navaid of the given type in the + database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + database. You must pass exactly one nav aid type to this routine. + } + FUNCTION XPLMFindLastNavAidOfType( + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindNavAid + + This routine provides a number of searching capabilities for the nav + database. XPLMFindNavAid will search through every nav aid whose type is + within inType (multiple types may be added together) and return any + nav-aids found based on the following rules: + + * If inLat and inLon are not NULL, the navaid nearest to that lat/lon will + be returned, otherwise the last navaid found will be returned. + + * If inFrequency is not NULL, then any navaids considered must match this + frequency. Note that this will screen out radio beacons that do not have + frequency data published (like inner markers) but not fixes and airports. + + * If inNameFragment is not NULL, only navaids that contain the fragment in + their name will be returned. + + * If inIDFragment is not NULL, only navaids that contain the fragment in + their IDs will be returned. + + This routine provides a simple way to do a number of useful searches: + * Find the nearest navaid on this frequency. + * Find the nearest airport. + * Find the VOR whose ID is "KBOS". + * Find the nearest airport whose name contains "Chicago". + } + FUNCTION XPLMFindNavAid( + inNameFragment : XPLMString; { Can be nil } + inIDFragment : XPLMString; { Can be nil } + inLat : PSingle; { Can be nil } + inLon : PSingle; { Can be nil } + inFrequency : PInteger; { Can be nil } + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMGetNavAidInfo + + This routine returns information about a navaid. Any non-null field is + filled out with information if it is available. + + Frequencies are in the nav.dat convention as described in the X-Plane nav + database FAQ: NDB frequencies are exact, all others are multiplied by 100. + + The buffer for IDs should be at least 6 chars and the buffer for names + should be at least 41 chars, but since these values are likely to go up, I + recommend passing at least 32 chars for IDs and 256 chars for names when + possible. + + The outReg parameter tells if the navaid is within the local "region" of + loaded DSFs. (This information may not be particularly useful to plugins.) + The parameter is a single byte value 1 for true or 0 for false, not a C + string. + } + PROCEDURE XPLMGetNavAidInfo( + inRef : XPLMNavRef; + outType : PXPLMNavType; { Can be nil } + outLatitude : PSingle; { Can be nil } + outLongitude : PSingle; { Can be nil } + outHeight : PSingle; { Can be nil } + outFrequency : PInteger; { Can be nil } + outHeading : PSingle; { Can be nil } + outID : XPLMString; { Can be nil } + outName : XPLMString; { Can be nil } + outReg : XPLMString); { Can be nil } + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * FLIGHT MANAGEMENT COMPUTER + ___________________________________________________________________________} +{ + Note: the FMS works based on an array of entries. Indices into the array + are zero-based. Each entry is a nav-aid plus an altitude. The FMS tracks + the currently displayed entry and the entry that it is flying to. + + The FMS must be programmed with contiguous entries, so clearing an entry at + the end shortens the effective flight plan. There is a max of 100 + waypoints in the flight plan. +} + + + { + XPLMCountFMSEntries + + This routine returns the number of entries in the FMS. + } + FUNCTION XPLMCountFMSEntries: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDisplayedFMSEntry + + This routine returns the index of the entry the pilot is viewing. + } + FUNCTION XPLMGetDisplayedFMSEntry: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDestinationFMSEntry + + This routine returns the index of the entry the FMS is flying to. + } + FUNCTION XPLMGetDestinationFMSEntry: Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDisplayedFMSEntry + + This routine changes which entry the FMS is showing to the index specified. + } + PROCEDURE XPLMSetDisplayedFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetDestinationFMSEntry + + This routine changes which entry the FMS is flying the aircraft toward. + } + PROCEDURE XPLMSetDestinationFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetFMSEntryInfo + + This routine returns information about a given FMS entry. If the entry is + an airport or navaid, a reference to a nav entry can be returned allowing + you to find additional information (such as a frequency, ILS heading, name, + etc.). Note that this reference can be XPLM_NAV_NOT_FOUND until the + information has been looked up asynchronously, so after flightplan changes, + it might take up to a second for this field to become populated. The other + information is available immediately. For a lat/lon entry, the lat/lon is + returned by this routine but the navaid cannot be looked up (and the + reference will be XPLM_NAV_NOT_FOUND). FMS name entry buffers should be at + least 256 chars in length. + + WARNING: Due to a bug in X-Plane prior to 11.31, the navaid reference will + not be set to XPLM_NAV_NOT_FOUND while no data is available, and instead + just remain the value of the variable that you passed the pointer to. + Therefore, always initialize the variable to XPLM_NAV_NOT_FOUND before + passing the pointer to this function. + } + PROCEDURE XPLMGetFMSEntryInfo( + inIndex : Integer; + outType : PXPLMNavType; { Can be nil } + outID : XPLMString; { Can be nil } + outRef : PXPLMNavRef; { Can be nil } + outAltitude : PInteger; { Can be nil } + outLat : PSingle; { Can be nil } + outLon : PSingle); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetFMSEntryInfo + + This routine changes an entry in the FMS to have the destination navaid + passed in and the altitude specified. Use this only for airports, fixes, + and radio-beacon navaids. Currently of radio beacons, the FMS can only + support VORs and NDBs. Use the routines below to clear or fly to a lat/lon. + } + PROCEDURE XPLMSetFMSEntryInfo( + inIndex : Integer; + inRef : XPLMNavRef; + inAltitude : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetFMSEntryLatLon + + This routine changes the entry in the FMS to a lat/lon entry with the given + coordinates. + } + PROCEDURE XPLMSetFMSEntryLatLon( + inIndex : Integer; + inLat : Single; + inLon : Single; + inAltitude : Integer); + cdecl; external XPLM_DLL; + + { + XPLMClearFMSEntry + + This routine clears the given entry, potentially shortening the flight + plan. + } + PROCEDURE XPLMClearFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * GPS RECEIVER + ___________________________________________________________________________} +{ + These APIs let you read data from the GPS unit. +} + + { + XPLMGetGPSDestinationType + + This routine returns the type of the currently selected GPS destination, + one of fix, airport, VOR or NDB. + } + FUNCTION XPLMGetGPSDestinationType: XPLMNavType; + cdecl; external XPLM_DLL; + + { + XPLMGetGPSDestination + + This routine returns the current GPS destination. + } + FUNCTION XPLMGetGPSDestination: XPLMNavRef; + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMPlanes.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMPlanes.pas new file mode 100644 index 0000000..3801f0a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMPlanes.pas @@ -0,0 +1,278 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMPlanes; +INTERFACE +{ + The XPLMPlanes APIs allow you to control the various aircraft in X-Plane, + both the user's and the sim's. + + *Note*: unlike almost all other APIs in the SDK, aircraft paths are _full_ + file system paths for historical reasons. You'll need to prefix all + relative paths with the X-Plane path as accessed via XPLMGetSystemPath. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * USER AIRCRAFT ACCESS + ___________________________________________________________________________} + + { + XPLMSetUsersAircraft + + This routine changes the user's aircraft. Note that this will reinitialize + the user to be on the nearest airport's first runway. Pass in a full path + (hard drive and everything including the .acf extension) to the .acf file. + } + PROCEDURE XPLMSetUsersAircraft( + inAircraftPath : XPLMString); + cdecl; external XPLM_DLL; + { + XPLMPlaceUserAtAirport + + This routine places the user at a given airport. Specify the airport by + its X-Plane airport ID (e.g. 'KBOS'). + } + PROCEDURE XPLMPlaceUserAtAirport( + inAirportCode : XPLMString); + cdecl; external XPLM_DLL; +{$IFDEF XPLM300} + { + XPLMPlaceUserAtLocation + + Places the user at a specific location after performing any necessary + scenery loads. + + As with in-air starts initiated from the X-Plane user interface, the + aircraft will always start with its engines running, regardless of the + user's preferences (i.e., regardless of what the dataref + `sim/operation/prefs/startup_running` says). + } + PROCEDURE XPLMPlaceUserAtLocation( + latitudeDegrees : Real; + longitudeDegrees : Real; + elevationMetersMSL : Single; + headingDegreesTrue : Single; + speedMetersPerSecond: Single); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} +{___________________________________________________________________________ + * GLOBAL AIRCRAFT ACCESS + ___________________________________________________________________________} + +CONST + { The user's aircraft is always index 0. } + XPLM_USER_AIRCRAFT = 0; +{$IFDEF XPLM_DEPRECATED} + { + XPLMPlaneDrawState_t + + This structure contains additional plane parameter info to be passed to + draw plane. Make sure to fill in the size of the structure field with + sizeof(XPLMDrawPlaneState_t) so that the XPLM can tell how many fields you + knew about when compiling your plugin (since more fields may be added + later). + + Most of these fields are ratios from 0 to 1 for control input. X-Plane + calculates what the actual controls look like based on the .acf file for + that airplane. Note for the yoke inputs, this is what the pilot of the + plane has commanded (post artificial stability system if there were one) + and affects aelerons, rudder, etc. It is not necessarily related to the + actual position of the plane! + } +TYPE + XPLMPlaneDrawState_t = RECORD + { The size of the draw state struct. } + structSize : Integer; + { A ratio from [0..1] describing how far the landing gear is extended. } + gearPosition : Single; + { Ratio of flap deployment, 0 = up, 1 = full deploy. } + flapRatio : Single; + { Ratio of spoiler deployment, 0 = none, 1 = full deploy. } + spoilerRatio : Single; + { Ratio of speed brake deployment, 0 = none, 1 = full deploy. } + speedBrakeRatio : Single; + { Ratio of slat deployment, 0 = none, 1 = full deploy. } + slatRatio : Single; + { Wing sweep ratio, 0 = forward, 1 = swept. } + wingSweep : Single; + { Thrust power, 0 = none, 1 = full fwd, -1 = full reverse. } + thrust : Single; + { Total pitch input for this plane. } + yokePitch : Single; + { Total Heading input for this plane. } + yokeHeading : Single; + { Total Roll input for this plane. } + yokeRoll : Single; + END; + PXPLMPlaneDrawState_t = ^XPLMPlaneDrawState_t; +{$ENDIF XPLM_DEPRECATED} + { + XPLMCountAircraft + + This function returns the number of aircraft X-Plane is capable of having, + as well as the number of aircraft that are currently active. These numbers + count the user's aircraft. It can also return the plugin that is currently + controlling aircraft. In X-Plane 7, this routine reflects the number of + aircraft the user has enabled in the rendering options window. + } + PROCEDURE XPLMCountAircraft( + outTotalAircraft : PInteger; + outActiveAircraft : PInteger; + outController : PXPLMPluginID); + cdecl; external XPLM_DLL; + { + XPLMGetNthAircraftModel + + This function returns the aircraft model for the Nth aircraft. Indices are + zero based, with zero being the user's aircraft. The file name should be + at least 256 chars in length; the path should be at least 512 chars in + length. + } + PROCEDURE XPLMGetNthAircraftModel( + inIndex : Integer; + outFileName : XPLMString; + outPath : XPLMString); + cdecl; external XPLM_DLL; +{___________________________________________________________________________ + * EXCLUSIVE AIRCRAFT ACCESS + ___________________________________________________________________________} +{ + The following routines require exclusive access to the airplane APIs. Only + one plugin may have this access at a time. +} + + + { + XPLMPlanesAvailable_f + + Your airplanes available callback is called when another plugin gives up + access to the multiplayer planes. Use this to wait for access to + multiplayer. + } +TYPE + XPLMPlanesAvailable_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMAcquirePlanes + + XPLMAcquirePlanes grants your plugin exclusive access to the aircraft. It + returns 1 if you gain access, 0 if you do not. + + inAircraft - pass in an array of pointers to strings specifying the planes + you want loaded. For any plane index you do not want loaded, pass a + 0-length string. Other strings should be full paths with the .acf + extension. NULL terminates this array, or pass NULL if there are no planes + you want loaded. + + If you pass in a callback and do not receive access to the planes your + callback will be called when the airplanes are available. If you do receive + airplane access, your callback will not be called. + } + FUNCTION XPLMAcquirePlanes( + inAircraft : PXPLMString; { Can be nil } + inCallback : XPLMPlanesAvailable_f; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMReleasePlanes + + Call this function to release access to the planes. Note that if you are + disabled, access to planes is released for you and you must reacquire it. + } + PROCEDURE XPLMReleasePlanes; + cdecl; external XPLM_DLL; + + { + XPLMSetActiveAircraftCount + + This routine sets the number of active planes. If you pass in a number + higher than the total number of planes availables, only the total number of + planes available is actually used. + } + PROCEDURE XPLMSetActiveAircraftCount( + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetAircraftModel + + This routine loads an aircraft model. It may only be called if you have + exclusive access to the airplane APIs. Pass in the path of the model with + the .acf extension. The index is zero based, but you may not pass in 0 + (use XPLMSetUsersAircraft to load the user's aircracft). + } + PROCEDURE XPLMSetAircraftModel( + inIndex : Integer; + inAircraftPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMDisableAIForPlane + + This routine turns off X-Plane's AI for a given plane. The plane will + continue to draw and be a real plane in X-Plane, but will not move itself. + } + PROCEDURE XPLMDisableAIForPlane( + inPlaneIndex : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM_DEPRECATED} + { + XPLMDrawAircraft + + WARNING: Aircraft drawing via this API is deprecated and will not work in + future versions of X-Plane. Use XPLMInstance for 3-d drawing of custom + aircraft models. + + This routine draws an aircraft. It can only be called from a 3-d drawing + callback. Pass in the position of the plane in OpenGL local coordinates + and the orientation of the plane. A 1 for full drawing indicates that the + whole plane must be drawn; a 0 indicates you only need the nav lights + drawn. (This saves rendering time when planes are far away.) + } + PROCEDURE XPLMDrawAircraft( + inPlaneIndex : Integer; + inX : Single; + inY : Single; + inZ : Single; + inPitch : Single; + inRoll : Single; + inYaw : Single; + inFullDraw : Integer; + inDrawStateInfo : PXPLMPlaneDrawState_t); + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMReinitUsersPlane + + WARNING: DO NOT USE. Use XPLMPlaceUserAtAirport or + XPLMPlaceUserAtLocation. + + This function recomputes the derived flight model data from the aircraft + structure in memory. If you have used the data access layer to modify the + aircraft structure, use this routine to resynchronize X-Plane; since + X-Plane works at least partly from derived values, the sim will not behave + properly until this is called. + + WARNING: this routine does not necessarily place the airplane at the + airport; use XPLMSetUsersAircraft to be compatible. This routine is + provided to do special experimentation with flight models without resetting + flight. + } + PROCEDURE XPLMReinitUsersPlane; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMPlugin.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMPlugin.pas new file mode 100644 index 0000000..83fbb73 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMPlugin.pas @@ -0,0 +1,413 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMPlugin; +INTERFACE +{ + These APIs provide facilities to find and work with other plugins and + manage other plugins. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FINDING PLUGINS + ___________________________________________________________________________} +{ + These APIs allow you to find another plugin or yourself, or iterate across + all plugins. For example, if you wrote an FMS plugin that needed to talk + to an autopilot plugin, you could use these APIs to locate the autopilot + plugin. +} + + + { + XPLMGetMyID + + This routine returns the plugin ID of the calling plug-in. Call this to + get your own ID. + } + FUNCTION XPLMGetMyID: XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMCountPlugins + + This routine returns the total number of plug-ins that are loaded, both + disabled and enabled. + } + FUNCTION XPLMCountPlugins: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetNthPlugin + + This routine returns the ID of a plug-in by index. Index is 0 based from 0 + to XPLMCountPlugins-1, inclusive. Plugins may be returned in any arbitrary + order. + } + FUNCTION XPLMGetNthPlugin( + inIndex : Integer) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMFindPluginByPath + + This routine returns the plug-in ID of the plug-in whose file exists at the + passed in absolute file system path. XPLM_NO_PLUGIN_ID is returned if the + path does not point to a currently loaded plug-in. + } + FUNCTION XPLMFindPluginByPath( + inPath : XPLMString) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMFindPluginBySignature + + This routine returns the plug-in ID of the plug-in whose signature matches + what is passed in or XPLM_NO_PLUGIN_ID if no running plug-in has this + signature. Signatures are the best way to identify another plug-in as they + are independent of the file system path of a plug-in or the human-readable + plug-in name, and should be unique for all plug-ins. Use this routine to + locate another plugin that your plugin interoperates with + } + FUNCTION XPLMFindPluginBySignature( + inSignature : XPLMString) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMGetPluginInfo + + This routine returns information about a plug-in. Each parameter should be + a pointer to a buffer of at least + 256 characters, or NULL to not receive the information. + + outName - the human-readable name of the plug-in. outFilePath - the + absolute file path to the file that contains this plug-in. outSignature - a + unique string that identifies this plug-in. outDescription - a + human-readable description of this plug-in. + } + PROCEDURE XPLMGetPluginInfo( + inPlugin : XPLMPluginID; + outName : XPLMString; { Can be nil } + outFilePath : XPLMString; { Can be nil } + outSignature : XPLMString; { Can be nil } + outDescription : XPLMString); { Can be nil } + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * ENABLING/DISABLING PLUG-INS + ___________________________________________________________________________} +{ + These routines are used to work with plug-ins and manage them. Most + plugins will not need to use these APIs. +} + + + { + XPLMIsPluginEnabled + + Returns whether the specified plug-in is enabled for running. + } + FUNCTION XPLMIsPluginEnabled( + inPluginID : XPLMPluginID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMEnablePlugin + + This routine enables a plug-in if it is not already enabled. It returns 1 + if the plugin was enabled or successfully enables itself, 0 if it does not. + Plugins may fail to enable (for example, if resources cannot be acquired) + by returning 0 from their XPluginEnable callback. + } + FUNCTION XPLMEnablePlugin( + inPluginID : XPLMPluginID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMDisablePlugin + + This routine disableds an enabled plug-in. + } + PROCEDURE XPLMDisablePlugin( + inPluginID : XPLMPluginID); + cdecl; external XPLM_DLL; + + { + XPLMReloadPlugins + + This routine reloads all plug-ins. Once this routine is called and you + return from the callback you were within (e.g. a menu select callback) you + will receive your XPluginDisable and XPluginStop callbacks and your DLL + will be unloaded, then the start process happens as if the sim was starting + up. + } + PROCEDURE XPLMReloadPlugins; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * INTERPLUGIN MESSAGING + ___________________________________________________________________________} +{ + Plugin messages are defined as 32-bit integers. Messages below 0x00FFFFFF + are reserved for X-Plane and the plugin SDK. + + Messages come with a pointer parameter; the meaning of this pointer depends + on the message itself. In some messages, the pointer parameter contains an + actual typed pointer to data that can be inspected in the plugin; in these + cases the documentation will state that the parameter "points to" + information. + + in other cases, the value of the pointer is actually an integral number + stuffed into the pointer's storage. In these second cases, the pointer + parameter needs to be cast, not dereferenced. In these caess, the + documentation will state that the parameter "contains" a value, which will + always be an integral type. + + Some messages don't use the pointer parameter - in this case your plugin + should ignore it. + + Messages have two conceptual uses: notifications and commands. Commands + are sent from one plugin to another to induce behavior; notifications are + sent from one plugin to all others for informational purposes. It is + important that commands and notifications not have the same values because + this could cause a notification sent by one plugin to accidentally induce a + command in another. + + By convention, plugin-defined notifications should have the high bit set + (e.g. be greater or equal to unsigned 0x8000000) while commands should have + this bit be cleared. + + The following messages are sent to your plugin by X-Plane. +} + + +CONST + { This message is sent to your plugin whenever the user's plane crashes. The } + { parameter is ignored. } + XPLM_MSG_PLANE_CRASHED = 101; + + { This message is sent to your plugin whenever a new plane is loaded. The } + { parameter contains the index number of the plane being loaded; 0 indicates } + { the user's plane. } + XPLM_MSG_PLANE_LOADED = 102; + + { This messages is sent whenever the user's plane is positioned at a new } + { airport. The parameter is ignored. } + XPLM_MSG_AIRPORT_LOADED = 103; + + { This message is sent whenever new scenery is loaded. Use datarefs to } + { determine the new scenery files that were loaded. The parameter is ignored.} + XPLM_MSG_SCENERY_LOADED = 104; + + { This message is sent whenever the user adjusts the number of X-Plane } + { aircraft models. You must use XPLMCountPlanes to find out how many planes } + { are now available. This message will only be sent in XP7 and higher } + { because in XP6 the number of aircraft is not user-adjustable. The parameter} + { is ignored. } + XPLM_MSG_AIRPLANE_COUNT_CHANGED = 105; + +{$IFDEF XPLM200} +CONST + { This message is sent to your plugin whenever a plane is unloaded. The } + { parameter contains the index number of the plane being unloaded; 0 } + { indicates the user's plane. The parameter is of type int, passed as the } + { value of the pointer. (That is: the parameter is an int, not a pointer to } + { an int.) } + XPLM_MSG_PLANE_UNLOADED = 106; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} +CONST + { This message is sent to your plugin right before X-Plane writes its } + { preferences file. You can use this for two purposes: to write your own } + { preferences, and to modify any datarefs to influence preferences output. } + { For example, if your plugin temporarily modifies saved preferences, you can} + { put them back to their default values here to avoid having the tweaks be } + { persisted if your plugin is not loaded on the next invocation of X-Plane. } + { The parameter is ignored. } + XPLM_MSG_WILL_WRITE_PREFS = 107; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { This message is sent to your plugin right after a livery is loaded for an } + { airplane. You can use this to check the new livery (via datarefs) and } + { react accordingly. The parameter contains the index number of the aircraft} + { whose livery is changing. } + XPLM_MSG_LIVERY_LOADED = 108; +{$ENDIF XPLM210} + +{$IFDEF XPLM301} +CONST + { Sent to your plugin right before X-Plane enters virtual reality mode (at } + { which time any windows that are not positioned in VR mode will no longer be} + { visible to the user). The parameter is unused and should be ignored. } + XPLM_MSG_ENTERED_VR = 109; +{$ENDIF XPLM301} + +{$IFDEF XPLM301} + { Sent to your plugin right before X-Plane leaves virtual reality mode (at } + { which time you may want to clean up windows that are positioned in VR } + { mode). The parameter is unused and should be ignored. } + XPLM_MSG_EXITING_VR = 110; +{$ENDIF XPLM301} + +{$IFDEF XPLM303} +CONST + { Sent to your plugin if another plugin wants to take over AI planes. If you } + { are a synthetic traffic provider, that probably means a plugin for an } + { online network has connected and wants to supply aircraft flown by real } + { humans and you should cease to provide synthetic traffic. If however you } + { are providing online traffic from real humans, you probably don't want to } + { disconnect, in which case you just ignore this message. The sender is the } + { plugin ID of the plugin asking for control of the planes now. You can use } + { it to find out who is requesting and whether you should yield to them. } + { Synthetic traffic providers should always yield to online networks. The } + { parameter is unused and should be ignored. } + XPLM_MSG_RELEASE_PLANES = 111; +{$ENDIF XPLM303} + + { + XPLMSendMessageToPlugin + + This function sends a message to another plug-in or X-Plane. Pass + XPLM_NO_PLUGIN_ID to broadcast to all plug-ins. Only enabled plug-ins with + a message receive function receive the message. + } + PROCEDURE XPLMSendMessageToPlugin( + inPlugin : XPLMPluginID; + inMessage : Integer; + inParam : pointer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Plugin Features API + ___________________________________________________________________________} +{ + The plugin features API allows your plugin to "sign up" for additional + capabilities and plugin system features that are normally disabled for + backward compatibility. This allows advanced plugins to "opt-in" to new + behavior. + + Each feature is defined by a permanent string name. The feature string + names will vary with the particular installation of X-Plane, so plugins + should not expect a feature to be guaranteed present. + + XPLM_WANTS_REFLECTIONS + ---------------------- + + Available in the SDK 2.0 and later for X-Plane 9, enabling this capability + causes your plugin to receive drawing hook callbacks when X-Plane builds + its off-screen reflection and shadow rendering passes. Plugins should + enable this and examine the dataref sim/graphics/view/plane_render_type to + determine whether the drawing callback is for a reflection, shadow + calculation, or the main screen. Rendering can be simlified or omitted for + reflections, and non-solid drawing should be skipped for shadow + calculations. + + **Note**: direct drawing via draw callbacks is not recommended; use the + XPLMInstance API to create object models instead. + + XPLM_USE_NATIVE_PATHS + --------------------- + + available in the SDK 2.1 and later for X-Plane 10, this modifies the plugin + system to use Unix-style paths on all operating systems. With this enabled: + + * OS X paths will match the native OS X Unix. + * Windows will use forward slashes but preserve C:\ or another drive letter + when using complete file paths. + * Linux uses its native file system path scheme. + + Without this enabled: + + * OS X will use CFM file paths separated by a colon. + * Windows will use back-slashes and conventional DOS paths. + * Linux uses its native file system path scheme. + + All plugins should enable this feature on OS X to access the native file + system. + + XPLM_USE_NATIVE_WIDGET_WINDOWS + ------------------------------ + + Available in the SDK 3.0.2 SDK, this capability tells the widgets library + to use new, modern X-Plane backed XPLMDisplay windows to anchor all widget + trees. Without it, widgets will always use legacy windows. + + Plugins should enable this to allow their widget hierarchies to respond to + the user's UI size settings and to map widget-based windwos to a VR HMD. + + Before enabling this, make sure any custom widget code in your plugin is + prepared to cope with the UI coordinate system not being th same as the + OpenGL window coordinate system. +} + + + { + XPLMFeatureEnumerator_f + + You pass an XPLMFeatureEnumerator_f to get a list of all features supported + by a given version running version of X-Plane. This routine is called once + for each feature. + } +TYPE + XPLMFeatureEnumerator_f = PROCEDURE( + inFeature : XPLMString; + inRef : pointer); cdecl; + + { + XPLMHasFeature + + This returns 1 if the given installation of X-Plane supports a feature, or + 0 if it does not. + } + FUNCTION XPLMHasFeature( + inFeature : XPLMString) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMIsFeatureEnabled + + This returns 1 if a feature is currently enabled for your plugin, or 0 if + it is not enabled. It is an error to call this routine with an unsupported + feature. + } + FUNCTION XPLMIsFeatureEnabled( + inFeature : XPLMString) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMEnableFeature + + This routine enables or disables a feature for your plugin. This will + change the running behavior of X-Plane and your plugin in some way, + depending on the feature. + } + PROCEDURE XPLMEnableFeature( + inFeature : XPLMString; + inEnable : Integer); + cdecl; external XPLM_DLL; + + { + XPLMEnumerateFeatures + + This routine calls your enumerator callback once for each feature that this + running version of X-Plane supports. Use this routine to determine all of + the features that X-Plane can support. + } + PROCEDURE XPLMEnumerateFeatures( + inEnumerator : XPLMFeatureEnumerator_f; + inRef : pointer); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMProcessing.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMProcessing.pas new file mode 100644 index 0000000..e09b6e5 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMProcessing.pas @@ -0,0 +1,254 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMProcessing; +INTERFACE +{ + This API allows you to get regular callbacks during the flight loop, the + part of X-Plane where the plane's position calculates the physics of + flight, etc. Use these APIs to accomplish periodic tasks like logging data + and performing I/O. + + You can receive a callback either just before or just after the per-frame + physics calculations happen - you can use post-FM callbacks to "patch" the + flight model after it has run. + + If the user has set the number of flight model iterations per frame greater + than one your plugin will _not_ see this; these integrations run on the + sub-section of the flight model where iterations improve responsiveness + (e.g. physical integration, not simple systems tracking) and are thus + opaque to plugins. + + Flight loop scheduling, when scheduled by time, is scheduled by a "first + callback after the deadline" schedule, e.g. your callbacks will always be + slightly late to ensure that we don't run faster than your deadline. + + WARNING: Do NOT use these callbacks to draw! You cannot draw during flight + loop callbacks. Use the drawing callbacks (see XPLMDisplay for more info) + for graphics. (One exception: you can use a post-flight loop callback to + update your own off-screen FBOs.) +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FLIGHT LOOP CALLBACKS + ___________________________________________________________________________} + +{$IFDEF XPLM210} + { + XPLMFlightLoopPhaseType + + You can register a flight loop callback to run either before or after the + flight model is integrated by X-Plane. + } +TYPE + XPLMFlightLoopPhaseType = ( + { Your callback runs before X-Plane integrates the flight model. } + xplm_FlightLoop_Phase_BeforeFlightModel = 0 + + { Your callback runs after X-Plane integrates the flight model. } + ,xplm_FlightLoop_Phase_AfterFlightModel = 1 + + ); + PXPLMFlightLoopPhaseType = ^XPLMFlightLoopPhaseType; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMFlightLoopID + + This is an opaque identifier for a flight loop callback. You can use this + identifier to easily track and remove your callbacks, or to use the new + flight loop APIs. + } + XPLMFlightLoopID = pointer; + PXPLMFlightLoopID = ^XPLMFlightLoopID; +{$ENDIF XPLM210} + + { + XPLMFlightLoop_f + + This is your flight loop callback. Each time the flight loop is iterated + through, you receive this call at the end. + + Flight loop callbacks receive a number of input timing parameters. These + input timing parameters are not particularly useful; you may need to track + your own timing data (e.g. by reading datarefs). The input parameters are: + + - inElapsedSinceLastCall: the wall time since your last callback. + - inElapsedTimeSinceLastFlightLoop: the wall time since any flight loop was + dispatched. + - inCounter: a monotonically increasing counter, bumped once per flight + loop dispatch from the sim. + - inRefcon: your own ptr constant from when you regitered yor callback. + + Your return value controls when you will next be called. + + - Return 0 to stop receiving callbacks. + - Pass a positive number to specify how many seconds until the next + callback. (You will be called at or after this time, not before.) + - Pass a negative number to specify how many loops must go by until you + are called. For example, -1.0 means call me the very next loop. + + Try to run your flight loop as infrequently as is practical, and suspend it + (using return value 0) when you do not need it; lots of flight loop + callbacks that do nothing lowers X-Plane's frame rate. + + Your callback will NOT be unregistered if you return 0; it will merely be + inactive. + } +TYPE + XPLMFlightLoop_f = FUNCTION( + inElapsedSinceLastCall: Single; + inElapsedTimeSinceLastFlightLoop: Single; + inCounter : Integer; + inRefcon : pointer) : Single; cdecl; + +{$IFDEF XPLM210} + { + XPLMCreateFlightLoop_t + + XPLMCreateFlightLoop_t contains the parameters to create a new flight loop + callback. The strsucture can be expanded in future SDKs - always set + structSize to the size of your structure in bytes. + } +TYPE + XPLMCreateFlightLoop_t = RECORD + structSize : Integer; + phase : XPLMFlightLoopPhaseType; + callbackFunc : XPLMFlightLoop_f; + refcon : pointer; + END; + PXPLMCreateFlightLoop_t = ^XPLMCreateFlightLoop_t; +{$ENDIF XPLM210} + + { + XPLMGetElapsedTime + + This routine returns the elapsed time since the sim started up in decimal + seconds. This is a wall timer; it keeps counting upward even if the sim is + pasued. + + __WARNING__: XPLMGetElapsedTime is not a very good timer! It lacks + precision in both its data type and its source. Do not attempt to use it + for timing critical applications like network multiplayer. + } + FUNCTION XPLMGetElapsedTime: Single; + cdecl; external XPLM_DLL; + + { + XPLMGetCycleNumber + + This routine returns a counter starting at zero for each sim cycle + computed/video frame rendered. + } + FUNCTION XPLMGetCycleNumber: Integer; + cdecl; external XPLM_DLL; + + { + XPLMRegisterFlightLoopCallback + + This routine registers your flight loop callback. Pass in a pointer to a + flight loop function and a refcon. inInterval defines when you will be + called. Pass in a positive number to specify seconds from registration time + to the next callback. Pass in a negative number to indicate when you will + be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to not be + called; your callback will be inactive. + + (This legacy function only installs pre-flight-loop callbacks; use + XPLMCreateFlightLoop for more control.) + } + PROCEDURE XPLMRegisterFlightLoopCallback( + inFlightLoop : XPLMFlightLoop_f; + inInterval : Single; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMUnregisterFlightLoopCallback + + This routine unregisters your flight loop callback. Do NOT call it from + your flight loop callback. Once your flight loop callback is unregistered, + it will not be called again. + + Only use this on flight loops registered via + XPLMRegisterFlightLoopCallback. + } + PROCEDURE XPLMUnregisterFlightLoopCallback( + inFlightLoop : XPLMFlightLoop_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMSetFlightLoopCallbackInterval + + This routine sets when a callback will be called. Do NOT call it from your + callback; use the return value of the callback to change your callback + interval from inside your callback. + + inInterval is formatted the same way as in XPLMRegisterFlightLoopCallback; + positive for seconds, negative for cycles, and 0 for deactivating the + callback. If inRelativeToNow is 1, times are from the time of this call; + otherwise they are from the time the callback was last called (or the time + it was registered if it has never been called. + } + PROCEDURE XPLMSetFlightLoopCallbackInterval( + inFlightLoop : XPLMFlightLoop_f; + inInterval : Single; + inRelativeToNow : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM210} + { + XPLMCreateFlightLoop + + This routine creates a flight loop callback and returns its ID. The flight + loop callback is created using the input param struct, and is inited to be + unscheduled. + } + FUNCTION XPLMCreateFlightLoop( + inParams : PXPLMCreateFlightLoop_t) : XPLMFlightLoopID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMDestroyFlightLoop + + This routine destroys a flight loop callback by ID. Only call it on flight + loops created with the newer XPLMCreateFlightLoop API. + } + PROCEDURE XPLMDestroyFlightLoop( + inFlightLoopID : XPLMFlightLoopID); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMScheduleFlightLoop + + This routine schedules a flight loop callback for future execution. If + inInterval is negative, it is run in a certain number of frames based on + the absolute value of the input. If the interval is positive, it is a + duration in seconds. + + If inRelativeToNow is true, ties are interpretted relative to the time this + routine is called; otherwise they are relative to the last call time or the + time the flight loop was registered (if never called). + } + PROCEDURE XPLMScheduleFlightLoop( + inFlightLoopID : XPLMFlightLoopID; + inInterval : Single; + inRelativeToNow : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMScenery.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMScenery.pas new file mode 100644 index 0000000..a585830 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMScenery.pas @@ -0,0 +1,434 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMScenery; +INTERFACE +{ + This package contains APIs to interact with X-Plane's scenery system. +} + +USES + XPLMDefs; + {$A4} +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Terrain Y-Testing + ___________________________________________________________________________} +{ + The Y-testing API allows you to locate the physical scenery mesh. This + would be used to place dynamic graphics on top of the ground in a plausible + way or do physics interactions. + + The Y-test API works via probe objects, which are allocated by your plugin + and used to query terrain. Probe objects exist both to capture which + algorithm you have requested (see probe types) and also to cache query + information. + + Performance Guidelines + ---------------------- + + It is generally faster to use the same probe for nearby points and + different probes for different points. Try not to allocate more than + "hundreds" of probes at most. Share probes if you need more. Generally, + probing operations are expensive, and should be avoided via caching when + possible. + + Y testing returns a location on the terrain, a normal vectory, and a + velocity vector. The normal vector tells you the slope of the terrain at + that point. The velocity vector tells you if that terrain is moving (and is + in meters/second). For example, if your Y test hits the aircraft carrier + deck, this tells you the velocity of that point on the deck. + + Note: the Y-testing API is limited to probing the loaded scenery area, + which is approximately 300x300 km in X-Plane 9. Probes outside this area + will return the height of a 0 MSL sphere. +} + + + { + XPLMProbeType + + XPLMProbeType defines the type of terrain probe - each probe has a + different algorithm. (Only one type of probe is provided right now, but + future APIs will expose more flexible or poewrful or useful probes. + } +TYPE + XPLMProbeType = ( + { The Y probe gives you the location of the tallest physical scenery along } + { the Y axis going through the queried point. } + xplm_ProbeY = 0 + + ); + PXPLMProbeType = ^XPLMProbeType; + + { + XPLMProbeResult + + Probe results - possible results from a probe query. + } + XPLMProbeResult = ( + { The probe hit terrain and returned valid values. } + xplm_ProbeHitTerrain = 0 + + { An error in the API call. Either the probe struct size is bad, or the } + { probe is invalid or the type is mismatched for the specific query call. } + ,xplm_ProbeError = 1 + + { The probe call succeeded but there is no terrain under this point (perhaps } + { it is off the side of the planet?) } + ,xplm_ProbeMissed = 2 + + ); + PXPLMProbeResult = ^XPLMProbeResult; + + { + XPLMProbeRef + + An XPLMProbeRef is an opaque handle to a probe, used for querying the + terrain. + } + XPLMProbeRef = pointer; + PXPLMProbeRef = ^XPLMProbeRef; + + { + XPLMProbeInfo_t + + XPLMProbeInfo_t contains the results of a probe call. Make sure to set + structSize to the size of the struct before using it. + } + XPLMProbeInfo_t = RECORD + { Size of structure in bytes - always set this before calling the XPLM. } + structSize : Integer; + { Resulting X location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationX : Single; + { Resulting Y location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationY : Single; + { Resulting Z location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationZ : Single; + { X component of the normal vector to the terrain we found. } + normalX : Single; + { Y component of the normal vector to the terrain we found. } + normalY : Single; + { Z component of the normal vector to the terrain we found. } + normalZ : Single; + { X component of the velocity vector of the terrain we found. } + velocityX : Single; + { Y component of the velocity vector of the terrain we found. } + velocityY : Single; + { Z component of the velocity vector of the terrain we found. } + velocityZ : Single; + { Tells if the surface we hit is water (otherwise it is land). } + is_wet : Integer; + END; + PXPLMProbeInfo_t = ^XPLMProbeInfo_t; + + { + XPLMCreateProbe + + Creates a new probe object of a given type and returns. + } + FUNCTION XPLMCreateProbe( + inProbeType : XPLMProbeType) : XPLMProbeRef; + cdecl; external XPLM_DLL; + + { + XPLMDestroyProbe + + Deallocates an existing probe object. + } + PROCEDURE XPLMDestroyProbe( + inProbe : XPLMProbeRef); + cdecl; external XPLM_DLL; + + { + XPLMProbeTerrainXYZ + + Probes the terrain. Pass in the XYZ coordinate of the probe point, a probe + object, and an XPLMProbeInfo_t struct that has its structSize member set + properly. Other fields are filled in if we hit terrain, and a probe result + is returned. + } + FUNCTION XPLMProbeTerrainXYZ( + inProbe : XPLMProbeRef; + inX : Single; + inY : Single; + inZ : Single; + outInfo : PXPLMProbeInfo_t) : XPLMProbeResult; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * Magnetic Variation + ___________________________________________________________________________} +{ + Use the magnetic variation (more properly, the "magnetic declination") API + to find the offset of magnetic north from true north at a given latitude + and longitude within the simulator. + + In the real world, the Earth's magnetic field is irregular, such that true + north (the direction along a meridian toward the north pole) does not + necessarily match what a magnetic compass shows as north. + + Using this API ensures that you present the same offsets to users as + X-Plane's built-in instruments. +} + + + { + XPLMGetMagneticVariation + + Returns X-Plane's simulated magnetic variation (declination) at the + indication latitude and longitude. + } + FUNCTION XPLMGetMagneticVariation( + latitude : Real; + longitude : Real) : Single; + cdecl; external XPLM_DLL; + + { + XPLMDegTrueToDegMagnetic + + Converts a heading in degrees relative to true north into a value relative + to magnetic north at the user's current location. + } + FUNCTION XPLMDegTrueToDegMagnetic( + headingDegreesTrue : Single) : Single; + cdecl; external XPLM_DLL; + + { + XPLMDegMagneticToDegTrue + + Converts a heading in degrees relative to magnetic north at the user's + current location into a value relative to true north. + } + FUNCTION XPLMDegMagneticToDegTrue( + headingDegreesMagnetic: Single) : Single; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{___________________________________________________________________________ + * Object Drawing + ___________________________________________________________________________} +{ + The object drawing routines let you load and draw X-Plane OBJ files. + Objects are loaded by file path and managed via an opaque handle. X-Plane + naturally reference counts objects, so it is important that you balance + every successful call to XPLMLoadObject with a call to XPLMUnloadObject! +} + + +{$IFDEF XPLM200} +TYPE + { + XPLMObjectRef + + An XPLMObjectRef is a opaque handle to an .obj file that has been loaded + into memory. + } + XPLMObjectRef = pointer; + PXPLMObjectRef = ^XPLMObjectRef; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMDrawInfo_t + + The XPLMDrawInfo_t structure contains positioning info for one object that + is to be drawn. Be sure to set structSize to the size of the structure for + future expansion. + } + XPLMDrawInfo_t = RECORD + { Set this to the size of this structure! } + structSize : Integer; + { X location of the object in local coordinates. } + x : Single; + { Y location of the object in local coordinates. } + y : Single; + { Z location of the object in local coordinates. } + z : Single; + { Pitch in degres to rotate the object, positive is up. } + pitch : Single; + { Heading in local coordinates to rotate the object, clockwise. } + heading : Single; + { Roll to rotate the object. } + roll : Single; + END; + PXPLMDrawInfo_t = ^XPLMDrawInfo_t; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} + { + XPLMObjectLoaded_f + + You provide this callback when loading an object asynchronously; it will be + called once the object is loaded. Your refcon is passed back. The object + ref passed in is the newly loaded object (ready for use) or NULL if an + error occured. + + If your plugin is disabled, this callback will be delivered as soon as the + plugin is re-enabled. If your plugin is unloaded before this callback is + ever called, the SDK will release the object handle for you. + } +TYPE + XPLMObjectLoaded_f = PROCEDURE( + inObject : XPLMObjectRef; + inRefcon : pointer); cdecl; +{$ENDIF XPLM210} + +{$IFDEF XPLM200} + { + XPLMLoadObject + + This routine loads an OBJ file and returns a handle to it. If X-Plane has + already loaded the object, the handle to the existing object is returned. + Do not assume you will get the same handle back twice, but do make sure to + call unload once for every load to avoid "leaking" objects. The object will + be purged from memory when no plugins and no scenery are using it. + + The path for the object must be relative to the X-System base folder. If + the path is in the root of the X-System folder you may need to prepend ./ + to it; loading objects in the root of the X-System folder is STRONGLY + discouraged - your plugin should not dump art resources in the root folder! + + XPLMLoadObject will return NULL if the object cannot be loaded (either + because it is not found or the file is misformatted). This routine will + load any object that can be used in the X-Plane scenery system. + + It is important that the datarefs an object uses for animation already be + loaded before you load the object. For this reason it may be necessary to + defer object loading until the sim has fully started. + } + FUNCTION XPLMLoadObject( + inPath : XPLMString) : XPLMObjectRef; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} + { + XPLMLoadObjectAsync + + This routine loads an object asynchronously; control is returned to you + immediately while X-Plane loads the object. The sim will not stop flying + while the object loads. For large objects, it may be several seconds before + the load finishes. + + You provide a callback function that is called once the load has completed. + Note that if the object cannot be loaded, you will not find out until the + callback function is called with a NULL object handle. + + There is no way to cancel an asynchronous object load; you must wait for + the load to complete and then release the object if it is no longer + desired. + } + PROCEDURE XPLMLoadObjectAsync( + inPath : XPLMString; + inCallback : XPLMObjectLoaded_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMDrawObjects + + __Deprecation Warning__: use XPLMInstancing to draw 3-d objects by creating + instances, rather than these APIs from draw callbacks. + + XPLMDrawObjects draws an object from an OBJ file one or more times. You + pass in the object and an array of XPLMDrawInfo_t structs, one for each + place you would like the object to be drawn. + + X-Plane will attempt to cull the objects based on LOD and visibility, and + will pick the appropriate LOD. + + Lighting is a boolean; pass 1 to show the night version of object with + night-only lights lit up. Pass 0 to show the daytime version of the object. + + earth_relative controls the coordinate system. If this is 1, the rotations + you specify are applied to the object after its coordinate system is + transformed from local to earth-relative coordinates -- that is, an object + with no rotations will point toward true north and the Y axis will be up + against gravity. If this is 0, the object is drawn with your rotations from + local coordanates -- that is, an object with no rotations is drawn pointing + down the -Z axis and the Y axis of the object matches the local coordinate + Y axis. + } + PROCEDURE XPLMDrawObjects( + inObject : XPLMObjectRef; + inCount : Integer; + inLocations : PXPLMDrawInfo_t; + lighting : Integer; + earth_relative : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM200} + { + XPLMUnloadObject + + This routine marks an object as no longer being used by your plugin. + Objects are reference counted: once no plugins are using an object, it is + purged from memory. Make sure to call XPLMUnloadObject once for each + successful call to XPLMLoadObject. + } + PROCEDURE XPLMUnloadObject( + inObject : XPLMObjectRef); + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Library Access + ___________________________________________________________________________} +{ + The library access routines allow you to locate scenery objects via the + X-Plane library system. Right now library access is only provided for + objects, allowing plugin-drawn objects to be extended using the library + system. +} + + + { + XPLMLibraryEnumerator_f + + An XPLMLibraryEnumerator_f is a callback you provide that is called once + for each library element that is located. The returned paths will be + relative to the X-System folder. + } +TYPE + XPLMLibraryEnumerator_f = PROCEDURE( + inFilePath : XPLMString; + inRef : pointer); cdecl; + + { + XPLMLookupObjects + + This routine looks up a virtual path in the library system and returns all + matching elements. You provide a callback - one virtual path may match many + objects in the library. XPLMLookupObjects returns the number of objects + found. + + The latitude and longitude parameters specify the location the object will + be used. The library system allows for scenery packages to only provide + objects to certain local locations. Only objects that are allowed at the + latitude/longitude you provide will be returned. + } + FUNCTION XPLMLookupObjects( + inPath : XPLMString; + inLatitude : Single; + inLongitude : Single; + enumerator : XPLMLibraryEnumerator_f; + ref : pointer) : Integer; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMUtilities.pas b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMUtilities.pas new file mode 100644 index 0000000..121e28b --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/Delphi/XPLM/XPLMUtilities.pas @@ -0,0 +1,951 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMUtilities; +INTERFACE + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FILE UTILITIES + ___________________________________________________________________________} +{ + The XPLMUtilities file APIs provide some basic file and path functions for + use with X-Plane. + + Directory Separators + -------------------- + + The XPLM has two modes it can work in: + + * X-Plane native paths: all paths are UTF8 strings, using the unix forward + slash (/) as the directory separating character. In native path mode, + you use the same path format for all three operating systems. + + * Legacy OS paths: the directroy separator is \ for Windows, : for OS X, + and / for Linux; OS paths are encoded in MacRoman for OS X using legacy + HFS conventions, use the application code page for multi-byte encoding + on Unix using DOS path conventions, and use UTF-8 for Linux. + + While legacy OS paths are the default, we strongly encourage you to opt in + to native paths using the XPLMEnableFeature API. + + * All OS X plugins should enable native paths all of the time; if you do + not do this, you will have to convert all paths back from HFS to Unix + (and deal with MacRoman) - code written using native paths and the C + file APIs "just works" on OS X. + + * For Linux plugins, there is no difference between the two encodings. + + * Windows plugins will need to convert the UTF8 file paths to UTF16 for + use with the "wide" APIs. While it might seem tempting to stick with + legacy OS paths (and just use the "ANSI" Windows APIs), X-Plane is fully + unicode-capable, and will often be installed in paths where the user's + directories have no ACP encoding. + + Full and Relative Paths + ----------------------- + + Some of these APIs use full paths, but others use paths relative to the + user's X-Plane installation. This is documented on a per-API basis. +} + + +{$IFDEF XPLM200} + { + XPLMDataFileType + + These enums define types of data files you can load or unload using the + SDK. + } +TYPE + XPLMDataFileType = ( + { A situation (.sit) file, which starts off a flight in a given } + { configuration. } + xplm_DataFile_Situation = 1 + + { A situation movie (.smo) file, which replays a past flight. } + ,xplm_DataFile_ReplayMovie = 2 + + ); + PXPLMDataFileType = ^XPLMDataFileType; +{$ENDIF XPLM200} + + { + XPLMGetSystemPath + + This function returns the full path to the X-System folder. Note that this + is a directory path, so it ends in a trailing : or /. + + The buffer you pass should be at least 512 characters long. The path is + returned using the current native or OS path conventions. + } + PROCEDURE XPLMGetSystemPath( + outSystemPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetPrefsPath + + This routine returns a full path to a file that is within X-Plane's + preferences directory. (You should remove the file name back to the last + directory separator to get the preferences directory using + XPLMExtractFileAndPath.) + + The buffer you pass should be at least 512 characters long. The path is + returned using the current native or OS path conventions. + } + PROCEDURE XPLMGetPrefsPath( + outPrefsPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetDirectorySeparator + + This routine returns a string with one char and a null terminator that is + the directory separator for the current platform. This allows you to write + code that concatinates directory paths without having to #ifdef for + platform. The character returned will reflect the current file path mode. + } + FUNCTION XPLMGetDirectorySeparator: XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMExtractFileAndPath + + Given a full path to a file, this routine separates the path from the file. + If the path is a partial directory (e.g. ends in : or \) the trailing + directory separator is removed. This routine works in-place; a pointer to + the file part of the buffer is returned; the original buffer still starts + with the path and is null terminated with no trailing separator. + } + FUNCTION XPLMExtractFileAndPath( + inFullPath : XPLMString) : XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMGetDirectoryContents + + This routine returns a list of files in a directory (specified by a full + path, no trailing : or \). The output is returned as a list of NULL + terminated strings. An index array (if specified) is filled with pointers + into the strings. The last file is indicated by a zero-length string (and + NULL in the indices). This routine will return 1 if you had capacity for + all files or 0 if you did not. You can also skip a given number of files. + + * inDirectoryPath - a null terminated C string containing the full path to + the directory with no trailing directory char. + + * inFirstReturn - the zero-based index of the first file in the directory + to return. (Usually zero to fetch all in one pass.) + + * outFileNames - a buffer to receive a series of sequential null + terminated C-string file names. A zero-length C string will be appended + to the very end. + + * inFileNameBufSize - the size of the file name buffer in bytes. + + * outIndices - a pointer to an array of character pointers that will + become an index into the directory. The last file will be followed by a + NULL value. Pass NULL if you do not want indexing information. + + * inIndexCount - the max size of the index in entries. + + * outTotalFiles - if not NULL, this is filled in with the number of files + in the directory. + + * outReturnedFiles - if not NULL, the number of files returned by this + iteration. + + Return value: 1 if all info could be returned, 0 if there was a buffer + overrun. + + WARNING: Before X-Plane 7 this routine did not properly iterate through + directories. If X-Plane + 6 compatibility is needed, use your own code to iterate directories. + } + FUNCTION XPLMGetDirectoryContents( + inDirectoryPath : XPLMString; + inFirstReturn : Integer; + outFileNames : XPLMString; + inFileNameBufSize : Integer; + outIndices : PXPLMString; { Can be nil } + inIndexCount : Integer; + outTotalFiles : PInteger; { Can be nil } + outReturnedFiles : PInteger) : Integer; { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMLoadDataFile + + Loads a data file of a given type. Paths must be relative to the X-System + folder. To clear the replay, pass a NULL file name (this is only valid with + replay movies, not sit files). + } + FUNCTION XPLMLoadDataFile( + inFileType : XPLMDataFileType; + inFilePath : XPLMString) : Integer; { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMSaveDataFile + + Saves the current situation or replay; paths are relative to the X-System + folder. + } + FUNCTION XPLMSaveDataFile( + inFileType : XPLMDataFileType; + inFilePath : XPLMString) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{___________________________________________________________________________ + * X-PLANE MISC + ___________________________________________________________________________} + + { + XPLMHostApplicationID + + While the plug-in SDK is only accessible to plugins running inside X-Plane, + the original authors considered extending the API to other applications + that shared basic infrastructure with X-Plane. These enumerations are + hold-overs from that original roadmap; all values other than X-Plane are + deprecated. Your plugin should never need this enumeration. + } +TYPE + XPLMHostApplicationID = ( + xplm_Host_Unknown = 0 + + ,xplm_Host_XPlane = 1 + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_PlaneMaker = 2 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_WorldMaker = 3 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_Briefer = 4 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_PartMaker = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_YoungsMod = 6 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_XAuto = 7 +{$ENDIF XPLM_DEPRECATED} + + ); + PXPLMHostApplicationID = ^XPLMHostApplicationID; + + { + XPLMLanguageCode + + These enums define what language the sim is running in. These enumerations + do not imply that the sim can or does run in all of these languages; they + simply provide a known encoding in the event that a given sim version is + localized to a certain language. + } + XPLMLanguageCode = ( + xplm_Language_Unknown = 0 + + ,xplm_Language_English = 1 + + ,xplm_Language_French = 2 + + ,xplm_Language_German = 3 + + ,xplm_Language_Italian = 4 + + ,xplm_Language_Spanish = 5 + + ,xplm_Language_Korean = 6 + +{$IFDEF XPLM200} + ,xplm_Language_Russian = 7 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + ,xplm_Language_Greek = 8 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + ,xplm_Language_Japanese = 9 +{$ENDIF XPLM200} + +{$IFDEF XPLM300} + ,xplm_Language_Chinese = 10 +{$ENDIF XPLM300} + + ); + PXPLMLanguageCode = ^XPLMLanguageCode; + +{$IFDEF XPLM200} + { + XPLMError_f + + An XPLM error callback is a function that you provide to receive debugging + information from the plugin SDK. See XPLMSetErrorCallback for more + information. NOTE: for the sake of debugging, your error callback will be + called even if your plugin is not enabled, allowing you to receive debug + info in your XPluginStart and XPluginStop callbacks. To avoid causing logic + errors in the management code, do not call any other plugin routines from + your error callback - it is only meant for catching errors in the + debugging. + } +TYPE + XPLMError_f = PROCEDURE( + inMessage : XPLMString); cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMInitialized + + Deprecated: This function returns 1 if X-Plane has properly initialized the + plug-in system. If this routine returns 0, many XPLM functions will not + work. + + NOTE: because plugins are always called from within the XPLM, there is no + need to check for initialization; it will always return 1. This routine is + deprecated - you do not need to check it before continuing within your + plugin. + } + FUNCTION XPLMInitialized: Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + { + XPLMGetVersions + + This routine returns the revision of both X-Plane and the XPLM DLL. All + versions are three-digit decimal numbers (e.g. 606 for version 6.06 of + X-Plane); the current revision of the XPLM is 200 (2.00). This routine also + returns the host ID of the app running us. + + The most common use of this routine is to special-case around X-Plane + version-specific behavior. + } + PROCEDURE XPLMGetVersions( + outXPlaneVersion : PInteger; + outXPLMVersion : PInteger; + outHostID : PXPLMHostApplicationID); + cdecl; external XPLM_DLL; + + { + XPLMGetLanguage + + This routine returns the langauge the sim is running in. + } + FUNCTION XPLMGetLanguage: XPLMLanguageCode; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMFindSymbol + + This routine will attempt to find the symbol passed in the inString + parameter. If the symbol is found a pointer the function is returned, + othewise the function will return NULL. + + You can use XPLMFindSymbol to utilize newer SDK API features without + requiring newer versions of the SDK (and X-Plane) as your minimum X-Plane + version as follows: + + * Define the XPLMnnn macro to the minimum required XPLM version you will + ship with (e.g. XPLM210 for X-Plane 10 compatibility). + + * Use XPLMGetVersions and XPLMFindSymbol to detect that the host sim is + new enough to use new functions and resolve function pointers. + + * Conditionally use the new functions if and only if XPLMFindSymbol only + returns a non- NULL pointer. + + Warning: you should always check the XPLM API version as well as the + results of XPLMFindSymbol to determine if funtionality is safe to use. + + To use functionality via XPLMFindSymbol you will need to copy your own + definitions of the X-Plane API prototypes and cast the returned pointer to + the correct type. + } + FUNCTION XPLMFindSymbol( + inString : XPLMString) : pointer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMSetErrorCallback + + XPLMSetErrorCallback installs an error-reporting callback for your plugin. + Normally the plugin system performs minimum diagnostics to maximize + performance. When you install an error callback, you will receive calls due + to certain plugin errors, such as passing bad parameters or incorrect data. + + Important: the error callback determines *programming* errors, e.g. bad API + parameters. Every error that is returned by the error callback represents a + mistake in your plugin that you should fix. Error callbacks are not used to + report expected run-time problems (e.g. disk I/O errors). + + The intention is for you to install the error callback during debug + sections and put a break-point inside your callback. This will cause you to + break into the debugger from within the SDK at the point in your plugin + where you made an illegal call. + + Installing an error callback may activate error checking code that would + not normally run, and this may adversely affect performance, so do not + leave error callbacks installed in shipping plugins. Since the only useful + response to an error is to change code, error callbacks are not useful "in + the field". + } + PROCEDURE XPLMSetErrorCallback( + inCallback : XPLMError_f); + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + { + XPLMDebugString + + This routine outputs a C-style string to the Log.txt file. The file is + immediately flushed so you will not lose data. (This does cause a + performance penalty.) + + Please do *not* leave routine diagnostic logging enabled in your shipping + plugin. The X-Plane Log file is shared by X-Plane and every plugin in the + system, and plugins that (when functioning normally) print verbose log + output make it difficult for developers to find error conditions from other + parts of the system. + } + PROCEDURE XPLMDebugString( + inString : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMSpeakString + + This function displays the string in a translucent overlay over the current + display and also speaks the string if text-to-speech is enabled. The string + is spoken asynchronously, this function returns immediately. This function + may not speak or print depending on user preferences. + } + PROCEDURE XPLMSpeakString( + inString : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetVirtualKeyDescription + + Given a virtual key code (as defined in XPLMDefs.h) this routine returns a + human-readable string describing the character. This routine is provided + for showing users what keyboard mappings they have set up. The string may + read 'unknown' or be a blank or NULL string if the virtual key is unknown. + } + FUNCTION XPLMGetVirtualKeyDescription( + inVirtualKey : XPLMChar) : XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMReloadScenery + + XPLMReloadScenery reloads the current set of scenery. You can use this + function in two typical ways: simply call it to reload the scenery, picking + up any new installed scenery, .env files, etc. from disk. Or, change the + lat/ref and lon/ref data refs and then call this function to shift the + scenery environment. This routine is equivalent to picking "reload + scenery" from the developer menu. + } + PROCEDURE XPLMReloadScenery; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * X-PLANE COMMAND MANAGEMENT + ___________________________________________________________________________} +{ + The command management APIs let plugins interact with the command-system in + X-Plane, the abstraction behind keyboard presses and joystick buttons. This + API lets you create new commands and modify the behavior (or get + notification) of existing ones. + + X-Plane Command Phases + ---------------------- + + X-Plane commands are not instantaneous; they operate over a duration. + (Think of a joystick button press - you can press, hold down, and then + release the joystick button; X-Plane commands model this entire process.) + + An X-Plane command consists of three phases: a beginning, continuous + repetition, and an ending. The command may be repeated zero times in its + duration, followed by one command ending. Command begin and end messges are + balanced, but a command may be bound to more than one event source (e.g. a + keyboard key and a joystick button), in which case you may receive a second + begin during before any end). + + When you issue commands in the plugin system, you *must* balance every call + to XPLMCommandBegin with a call to XPLMCommandEnd with the same command + reference. + + Command Behavior Modification + ----------------------------- + + You can register a callback to handle a command either before or after + X-Plane does; if you receive the command before X-Plane you have the option + to either let X-Plane handle the command or hide the command from X-Plane. + This lets plugins both augment commands and replace them. + + If you register for an existing command, be sure that you are *consistent* + in letting X-Plane handle or not handle the command; you are responsible + for passing a *balanced* number of begin and end messages to X-Plane. (E.g. + it is not legal to pass all the begin messages to X-Plane but hide all the + end messages). +} + + + { + XPLMCommandPhase + + The phases of a command. + } +TYPE + XPLMCommandPhase = ( + { The command is being started. } + xplm_CommandBegin = 0 + + { The command is continuing to execute. } + ,xplm_CommandContinue = 1 + + { The command has ended. } + ,xplm_CommandEnd = 2 + + ); + PXPLMCommandPhase = ^XPLMCommandPhase; + + { + XPLMCommandRef + + A command ref is an opaque identifier for an X-Plane command. Command + references stay the same for the life of your plugin but not between + executions of X-Plane. Command refs are used to execute commands, create + commands, and create callbacks for particular commands. + + Note that a command is not "owned" by a particular plugin. Since many + plugins may participate in a command's execution, the command does not go + away if the plugin that created it is unloaded. + } + XPLMCommandRef = pointer; + PXPLMCommandRef = ^XPLMCommandRef; + + { + XPLMCommandCallback_f + + A command callback is a function in your plugin that is called when a + command is pressed. Your callback receives the command reference for the + particular command, the phase of the command that is executing, and a + reference pointer that you specify when registering the callback. + + Your command handler should return 1 to let processing of the command + continue to other plugins and X-Plane, or 0 to halt processing, potentially + bypassing X-Plane code. + } + XPLMCommandCallback_f = FUNCTION( + inCommand : XPLMCommandRef; + inPhase : XPLMCommandPhase; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMFindCommand + + XPLMFindCommand looks up a command by name, and returns its command + reference or NULL if the command does not exist. + } + FUNCTION XPLMFindCommand( + inName : XPLMString) : XPLMCommandRef; + cdecl; external XPLM_DLL; + + { + XPLMCommandBegin + + XPLMCommandBegin starts the execution of a command, specified by its + command reference. The command is "held down" until XPLMCommandEnd is + called. You must balance each XPLMCommandBegin call with an XPLMCommandEnd + call. + } + PROCEDURE XPLMCommandBegin( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCommandEnd + + XPLMCommandEnd ends the execution of a given command that was started with + XPLMCommandBegin. You must not issue XPLMCommandEnd for a command you did + not begin. + } + PROCEDURE XPLMCommandEnd( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCommandOnce + + This executes a given command momentarily, that is, the command begins and + ends immediately. This is the equivalent of calling XPLMCommandBegin() and + XPLMCommandEnd() back ot back. + } + PROCEDURE XPLMCommandOnce( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCreateCommand + + XPLMCreateCommand creates a new command for a given string. If the command + already exists, the existing command reference is returned. The description + may appear in user interface contexts, such as the joystick configuration + screen. + } + FUNCTION XPLMCreateCommand( + inName : XPLMString; + inDescription : XPLMString) : XPLMCommandRef; + cdecl; external XPLM_DLL; + + { + XPLMRegisterCommandHandler + + XPLMRegisterCommandHandler registers a callback to be called when a command + is executed. You provide a callback with a reference pointer. + + If inBefore is true, your command handler callback will be executed before + X-Plane executes the command, and returning 0 from your callback will + disable X-Plane's processing of the command. If inBefore is false, your + callback will run after X-Plane. (You can register a single callback both + before and after a command.) + } + PROCEDURE XPLMRegisterCommandHandler( + inComand : XPLMCommandRef; + inHandler : XPLMCommandCallback_f; + inBefore : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMUnregisterCommandHandler + + XPLMUnregisterCommandHandler removes a command callback registered with + XPLMRegisterCommandHandler. + } + PROCEDURE XPLMUnregisterCommandHandler( + inComand : XPLMCommandRef; + inHandler : XPLMCommandCallback_f; + inBefore : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} +{$IFDEF XPLM_DEPRECATED} +{___________________________________________________________________________ + * X-PLANE USER INTERACTION + ___________________________________________________________________________} +{ + WARNING: The legacy user interaction API is deprecated; while it was the + only way to run commands in X-Plane 6,7 and 8, it is obsolete, and was + replaced by the command system API in X-Plane 9. You should not use this + API; replace any of the calls below with XPLMCommand invocations based on + persistent command strings. The documentation that follows is for historic + reference only. + + The legacy user interaction APIs let you simulate commands the user can do + with a joystick, keyboard etc. Note that it is generally safer for future + compatibility to use one of these commands than to manipulate the + underlying sim data. +} + + + { + XPLMCommandKeyID + + These enums represent all the keystrokes available within X-Plane. They can + be sent to X-Plane directly. For example, you can reverse thrust using + these enumerations. + } +TYPE + XPLMCommandKeyID = ( + xplm_key_pause=0, + xplm_key_revthrust, + xplm_key_jettison, + xplm_key_brakesreg, + xplm_key_brakesmax, + xplm_key_gear, + xplm_key_timedn, + xplm_key_timeup, + xplm_key_fadec, + xplm_key_otto_dis, + xplm_key_otto_atr, + xplm_key_otto_asi, + xplm_key_otto_hdg, + xplm_key_otto_gps, + xplm_key_otto_lev, + xplm_key_otto_hnav, + xplm_key_otto_alt, + xplm_key_otto_vvi, + xplm_key_otto_vnav, + xplm_key_otto_nav1, + xplm_key_otto_nav2, + xplm_key_targ_dn, + xplm_key_targ_up, + xplm_key_hdgdn, + xplm_key_hdgup, + xplm_key_barodn, + xplm_key_baroup, + xplm_key_obs1dn, + xplm_key_obs1up, + xplm_key_obs2dn, + xplm_key_obs2up, + xplm_key_com1_1, + xplm_key_com1_2, + xplm_key_com1_3, + xplm_key_com1_4, + xplm_key_nav1_1, + xplm_key_nav1_2, + xplm_key_nav1_3, + xplm_key_nav1_4, + xplm_key_com2_1, + xplm_key_com2_2, + xplm_key_com2_3, + xplm_key_com2_4, + xplm_key_nav2_1, + xplm_key_nav2_2, + xplm_key_nav2_3, + xplm_key_nav2_4, + xplm_key_adf_1, + xplm_key_adf_2, + xplm_key_adf_3, + xplm_key_adf_4, + xplm_key_adf_5, + xplm_key_adf_6, + xplm_key_transpon_1, + xplm_key_transpon_2, + xplm_key_transpon_3, + xplm_key_transpon_4, + xplm_key_transpon_5, + xplm_key_transpon_6, + xplm_key_transpon_7, + xplm_key_transpon_8, + xplm_key_flapsup, + xplm_key_flapsdn, + xplm_key_cheatoff, + xplm_key_cheaton, + xplm_key_sbrkoff, + xplm_key_sbrkon, + xplm_key_ailtrimL, + xplm_key_ailtrimR, + xplm_key_rudtrimL, + xplm_key_rudtrimR, + xplm_key_elvtrimD, + xplm_key_elvtrimU, + xplm_key_forward, + xplm_key_down, + xplm_key_left, + xplm_key_right, + xplm_key_back, + xplm_key_tower, + xplm_key_runway, + xplm_key_chase, + xplm_key_free1, + xplm_key_free2, + xplm_key_spot, + xplm_key_fullscrn1, + xplm_key_fullscrn2, + xplm_key_tanspan, + xplm_key_smoke, + xplm_key_map, + xplm_key_zoomin, + xplm_key_zoomout, + xplm_key_cycledump, + xplm_key_replay, + xplm_key_tranID, + xplm_key_max + ); + PXPLMCommandKeyID = ^XPLMCommandKeyID; + + { + XPLMCommandButtonID + + These are enumerations for all of the things you can do with a joystick + button in X-Plane. They currently match the buttons menu in the equipment + setup dialog, but these enums will be stable even if they change in + X-Plane. + } + XPLMCommandButtonID = ( + xplm_joy_nothing=0, + xplm_joy_start_all, + xplm_joy_start_0, + xplm_joy_start_1, + xplm_joy_start_2, + xplm_joy_start_3, + xplm_joy_start_4, + xplm_joy_start_5, + xplm_joy_start_6, + xplm_joy_start_7, + xplm_joy_throt_up, + xplm_joy_throt_dn, + xplm_joy_prop_up, + xplm_joy_prop_dn, + xplm_joy_mixt_up, + xplm_joy_mixt_dn, + xplm_joy_carb_tog, + xplm_joy_carb_on, + xplm_joy_carb_off, + xplm_joy_trev, + xplm_joy_trm_up, + xplm_joy_trm_dn, + xplm_joy_rot_trm_up, + xplm_joy_rot_trm_dn, + xplm_joy_rud_lft, + xplm_joy_rud_cntr, + xplm_joy_rud_rgt, + xplm_joy_ail_lft, + xplm_joy_ail_cntr, + xplm_joy_ail_rgt, + xplm_joy_B_rud_lft, + xplm_joy_B_rud_rgt, + xplm_joy_look_up, + xplm_joy_look_dn, + xplm_joy_look_lft, + xplm_joy_look_rgt, + xplm_joy_glance_l, + xplm_joy_glance_r, + xplm_joy_v_fnh, + xplm_joy_v_fwh, + xplm_joy_v_tra, + xplm_joy_v_twr, + xplm_joy_v_run, + xplm_joy_v_cha, + xplm_joy_v_fr1, + xplm_joy_v_fr2, + xplm_joy_v_spo, + xplm_joy_flapsup, + xplm_joy_flapsdn, + xplm_joy_vctswpfwd, + xplm_joy_vctswpaft, + xplm_joy_gear_tog, + xplm_joy_gear_up, + xplm_joy_gear_down, + xplm_joy_lft_brake, + xplm_joy_rgt_brake, + xplm_joy_brakesREG, + xplm_joy_brakesMAX, + xplm_joy_speedbrake, + xplm_joy_ott_dis, + xplm_joy_ott_atr, + xplm_joy_ott_asi, + xplm_joy_ott_hdg, + xplm_joy_ott_alt, + xplm_joy_ott_vvi, + xplm_joy_tim_start, + xplm_joy_tim_reset, + xplm_joy_ecam_up, + xplm_joy_ecam_dn, + xplm_joy_fadec, + xplm_joy_yaw_damp, + xplm_joy_art_stab, + xplm_joy_chute, + xplm_joy_JATO, + xplm_joy_arrest, + xplm_joy_jettison, + xplm_joy_fuel_dump, + xplm_joy_puffsmoke, + xplm_joy_prerotate, + xplm_joy_UL_prerot, + xplm_joy_UL_collec, + xplm_joy_TOGA, + xplm_joy_shutdown, + xplm_joy_con_atc, + xplm_joy_fail_now, + xplm_joy_pause, + xplm_joy_rock_up, + xplm_joy_rock_dn, + xplm_joy_rock_lft, + xplm_joy_rock_rgt, + xplm_joy_rock_for, + xplm_joy_rock_aft, + xplm_joy_idle_hilo, + xplm_joy_lanlights, + xplm_joy_max + ); + PXPLMCommandButtonID = ^XPLMCommandButtonID; + + { + XPLMSimulateKeyPress + + This function simulates a key being pressed for X-Plane. The keystroke goes + directly to X-Plane; it is never sent to any plug-ins. However, since this + is a raw key stroke it may be mapped by the keys file or enter text into a + field. + + Deprecated: use XPLMCommandOnce + } + PROCEDURE XPLMSimulateKeyPress( + inKeyType : Integer; + inKey : Integer); + cdecl; external XPLM_DLL; + + { + XPLMCommandKeyStroke + + This routine simulates a command-key stroke. However, the keys are done by + function, not by actual letter, so this function works even if the user has + remapped their keyboard. Examples of things you might do with this include + pausing the simulator. + + Deprecated: use XPLMCommandOnce + } + PROCEDURE XPLMCommandKeyStroke( + inKey : XPLMCommandKeyID); + cdecl; external XPLM_DLL; + + { + XPLMCommandButtonPress + + This function simulates any of the actions that might be taken by pressing + a joystick button. However, this lets you call the command directly rather + than have to know which button is mapped where. Important: you must release + each button you press. The APIs are separate so that you can 'hold down' a + button for a fixed amount of time. + + Deprecated: use XPLMCommandBegin. + } + PROCEDURE XPLMCommandButtonPress( + inButton : XPLMCommandButtonID); + cdecl; external XPLM_DLL; + + { + XPLMCommandButtonRelease + + This function simulates any of the actions that might be taken by pressing + a joystick button. See XPLMCommandButtonPress. + + Deprecated: use XPLMCommandEnd. + } + PROCEDURE XPLMCommandButtonRelease( + inButton : XPLMCommandButtonID); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM_DEPRECATED} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/Libraries/Mac/XPLM.framework/XPLM b/XPLPro_Plugin_Source/SDK/Libraries/Mac/XPLM.framework/XPLM new file mode 100644 index 0000000000000000000000000000000000000000..334071184538ea16492dd9756e7132a1ac807b8d GIT binary patch literal 214288 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 z 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 TS<%ZqW?!K(x5o7TAO7=yXE5y9 literal 0 HcmV?d00001 diff --git a/XPLPro_Plugin_Source/SDK/Libraries/Mac/XPWidgets.framework/XPWidgets b/XPLPro_Plugin_Source/SDK/Libraries/Mac/XPWidgets.framework/XPWidgets new file mode 100644 index 0000000000000000000000000000000000000000..20e521a54c969c17c285bcd229ebda586777a35b GIT binary patch literal 48768 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 4 + #define WIDGET_API __attribute__((visibility("default"))) + #elif __MACH__ + #define WIDGET_API + #else + #define WIDGET_API __declspec(dllexport) + #endif + #else + #define WIDGET_API + #endif +#elif IBM + #if XPWIDGETS + #define WIDGET_API __declspec(dllexport) + #else + #define WIDGET_API __declspec(dllimport) + #endif +#elif LIN + #if XPWIDGETS + #if __GNUC__ >= 4 + #define WIDGET_API __attribute__((visibility("default"))) + #else + #define WIDGET_API + #endif + #else + #define WIDGET_API + #endif +#else +#pragma error "Platform not defined!" +#endif + /*************************************************************************** + * WIDGET DEFINITIONS + ***************************************************************************/ +/* + * A widget is a call-back driven screen entity like a push-button, window, + * text entry field, etc. + * + * Use the widget API to create widgets of various classes. You can nest them + * into trees of widgets to create complex user interfaces. + * + */ + + +/* + * XPWidgetID + * + * A Widget ID is an opaque unique non-zero handle identifying your widget. + * Use 0 to specify "no widget". This type is defined as wide enough to hold a + * pointer. You receive a widget ID when you create a new widget and then use + * that widget ID to further refer to the widget. + * + */ +typedef void * XPWidgetID; + +/* + * XPWidgetPropertyID + * + * Properties are values attached to instances of your widgets. A property is + * identified by a 32-bit ID and its value is the width of a pointer. + * + * Each widget instance may have a property or not have it. When you set a + * property on a widget for the first time, the property is added to the + * widget; it then stays there for the life of the widget. + * + * Some property IDs are predefined by the widget package; you can make up + * your own property IDs as well. + * + */ +enum { + /* A window's refcon is an opaque value used by client code to find other data* + * based on it. */ + xpProperty_Refcon = 0, + + /* These properties are used by the utlities to implement dragging. */ + xpProperty_Dragging = 1, + + xpProperty_DragXOff = 2, + + xpProperty_DragYOff = 3, + + /* Is the widget hilited? (For widgets that support this kind of thing.) */ + xpProperty_Hilited = 4, + + /* Is there a C++ object attached to this widget? */ + xpProperty_Object = 5, + + /* If this property is 1, the widget package will use OpenGL to restrict * + * drawing to the Wiget's exposed rectangle. */ + xpProperty_Clip = 6, + + /* Is this widget enabled (for those that have a disabled state too)? */ + xpProperty_Enabled = 7, + + /* NOTE: Property IDs 1 - 999 are reserved for the widgets library. * + * * + * NOTE: Property IDs 1000 - 9999 are allocated to the standard widget classes* + * provided with the library. * + * * + * Properties 1000 - 1099 are for widget class 0, 1100 - 1199 for widget class* + * 1, etc. */ + xpProperty_UserStart = 10000, + + +}; +typedef int XPWidgetPropertyID; + +/* + * XPMouseState_t + * + * When the mouse is clicked or dragged, a pointer to this structure is passed + * to your widget function. + * + */ +typedef struct { + int x; + int y; + /* Mouse Button number, left = 0 (right button not yet supported. */ + int button; +#if defined(XPLM200) + /* Scroll wheel delta (button in this case would be the wheel axis number). */ + int delta; +#endif /* XPLM200 */ +} XPMouseState_t; + +/* + * XPKeyState_t + * + * When a key is pressed, a pointer to this struct is passed to your widget + * function. + * + */ +typedef struct { + /* The ASCII key that was pressed. WARNING: this may be 0 for some non-ASCII * + * key sequences. */ + char key; + /* The flags. Make sure to check this if you only want key-downs! */ + XPLMKeyFlags flags; + /* The virtual key code for the key */ + char vkey; +} XPKeyState_t; + +/* + * XPWidgetGeometryChange_t + * + * This structure contains the deltas for your widget's geometry when it + * changes. + * + */ +typedef struct { + int dx; + /* +Y = the widget moved up */ + int dy; + int dwidth; + int dheight; +} XPWidgetGeometryChange_t; + +/* + * XPDispatchMode + * + * The dispatching modes describe how the widgets library sends out messages. + * Currently there are three modes: + * + */ +enum { + /* The message will only be sent to the target widget. */ + xpMode_Direct = 0, + + /* The message is sent to the target widget, then up the chain of parents * + * until the message is handled or a parentless widget is reached. */ + xpMode_UpChain = 1, + + /* The message is sent to the target widget and then all of its children * + * recursively depth-first. */ + xpMode_Recursive = 2, + + /* The message is snet just to the target, but goes to every callback, even if* + * it is handled. */ + xpMode_DirectAllCallbacks = 3, + + /* The message is only sent to the very first handler even if it is not * + * accepted. (This is really only useful for some internal widget library * + * functions.) */ + xpMode_Once = 4, + + +}; +typedef int XPDispatchMode; + +/* + * XPWidgetClass + * + * Widget classes define predefined widget types. A widget class basically + * specifies from a library the widget function to be used for the widget. + * Most widgets can be made right from classes. + * + */ +typedef int XPWidgetClass; + +/* An unspecified widget class. Other widget classes are in * + * XPStandardWidgets.h */ +#define xpWidgetClass_None 0 + +/*************************************************************************** + * WIDGET MESSAGES + ***************************************************************************/ + +/* + * XPWidgetMessage + * + * Widgets receive 32-bit messages indicating what action is to be taken or + * notifications of events. The list of messages may be expanded. + * + */ +enum { + /* No message, should not be sent. */ + xpMsg_None = 0, + + /* The create message is sent once per widget that is created with your widget* + * function and once for any widget that has your widget function attached. * + * * + * Dispatching: Direct * + * * + * Param 1: 1 if you are being added as a subclass, 0 if the widget is first * + * being created. */ + xpMsg_Create = 1, + + /* The destroy message is sent once for each message that is destroyed that * + * has your widget function. * + * * + * Dispatching: Direct for all * + * * + * Param 1: 1 if being deleted by a recursive delete to the parent, 0 for * + * explicit deletion. */ + xpMsg_Destroy = 2, + + /* The paint message is sent to your widget to draw itself. The paint message * + * is the bare-bones message; in response you must draw yourself, draw your * + * children, set up clipping and culling, check for visibility, etc. If you * + * don't want to do all of this, ignore the paint message and a draw message * + * (see below) will be sent to you. * + * * + * Dispatching: Direct */ + xpMsg_Paint = 3, + + /* The draw message is sent to your widget when it is time to draw yourself. * + * OpenGL will be set up to draw in 2-d global screen coordinates, but you * + * should use the XPLM to set up OpenGL state. * + * * + * Dispatching: Direct */ + xpMsg_Draw = 4, + + /* The key press message is sent once per key that is pressed. The first * + * parameter is the type of key code (integer or char) and the second is the * + * code itself. By handling this event, you consume the key stroke. * + * * + * Handling this message 'consumes' the keystroke; not handling it passes it * + * to your parent widget. * + * * + * Dispatching: Up Chain * + * * + * Param 1: A pointer to an XPKeyState_t structure with the keystroke. */ + xpMsg_KeyPress = 5, + + /* Keyboard focus is being given to you. By handling this message you accept * + * keyboard focus. The first parameter will be one if a child of yours gave up* + * focus to you, 0 if someone set focus on you explicitly. * + * * + * Handling this message accepts focus; not handling refuses focus. * + * * + * Dispatching: direct * + * * + * Param 1: 1 if you are gaining focus because your child is giving it up, 0 * + * if someone is explicitly giving you focus. */ + xpMsg_KeyTakeFocus = 6, + + /* Keyboard focus is being taken away from you. The first parameter will be * + * one if you are losing focus because another widget is taking it, or 0 if * + * someone called the API to make you lose focus explicitly. * + * * + * Dispatching: Direct * + * * + * Param 1: 1 if focus is being taken by another widget, 0 if code requested * + * to remove focus. */ + xpMsg_KeyLoseFocus = 7, + + /* You receive one mousedown event per click with a mouse-state structure * + * pointed to by parameter 1, by accepting this you eat the click, otherwise * + * your parent gets it. You will not receive drag and mouse up messages if you* + * do not accept the down message. * + * * + * Handling this message consumes the mouse click, not handling it passes it * + * to the next widget. You can act 'transparent' as a window by never handling* + * moues clicks to certain areas. * + * * + * Dispatching: Up chain NOTE: Technically this is direct dispatched, but the * + * widgets library will shop it to each widget until one consumes the click, * + * making it effectively "up chain". * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseDown = 8, + + /* You receive a series of mouse drag messages (typically one per frame in the* + * sim) as the mouse is moved once you have accepted a mouse down message. * + * Parameter one points to a mouse-state structure describing the mouse * + * location. You will continue to receive these until the mouse button is * + * released. You may receive multiple mouse state messages with the same mouse* + * position. You will receive mouse drag events even if the mouse is dragged * + * out of your current or original bounds at the time of the mouse down. * + * * + * Dispatching: Direct * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseDrag = 9, + + /* The mouseup event is sent once when the mouse button is released after a * + * drag or click. You only receive this message if you accept the mouseDown * + * message. Parameter one points to a mouse state structure. * + * * + * Dispatching: Direct * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseUp = 10, + + /* Your geometry or a child's geometry is being changed. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the original reshaped target. * + * * + * Param 2: A pointer to a XPWidgetGeometryChange_t struct describing the * + * change. */ + xpMsg_Reshape = 11, + + /* Your exposed area has changed. * + * * + * Dispatching: Direct */ + xpMsg_ExposedChanged = 12, + + /* A child has been added to you. The child's ID is passed in parameter one. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of the child being added. */ + xpMsg_AcceptChild = 13, + + /* A child has been removed from to you. The child's ID is passed in parameter* + * one. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of the child being removed. */ + xpMsg_LoseChild = 14, + + /* You now have a new parent, or have no parent. The parent's ID is passed in,* + * or 0 for no parent. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of your parent */ + xpMsg_AcceptParent = 15, + + /* You or a child has been shown. Note that this does not include you being * + * shown because your parent was shown, you were put in a new parent, your * + * root was shown, etc. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the shown widget. */ + xpMsg_Shown = 16, + + /* You have been hidden. See limitations above. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the hidden widget. */ + xpMsg_Hidden = 17, + + /* Your descriptor has changed. * + * * + * Dispatching: Direct */ + xpMsg_DescriptorChanged = 18, + + /* A property has changed. Param 1 contains the property ID. * + * * + * Dispatching: Direct * + * * + * Param 1: The Property ID being changed. * + * * + * Param 2: The new property value */ + xpMsg_PropertyChanged = 19, + +#if defined(XPLM200) + /* The mouse wheel has moved. * + * * + * Return 1 to consume the mouse wheel move, or 0 to pass the message to a * + * parent. Dispatching: Up chain * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseWheel = 20, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* The cursor is over your widget. If you consume this message, change the * + * XPLMCursorStatus value to indicate the desired result, with the same rules * + * as in XPLMDisplay.h. * + * * + * Return 1 to consume this message, 0 to pass it on. * + * * + * Dispatching: Up chain Param 1: A pointer to an XPMouseState_t struct * + * containing the mouse status. * + * * + * Param 2: A pointer to a XPLMCursorStatus - set this to the cursor result * + * you desire. */ + xpMsg_CursorAdjust = 21, + +#endif /* XPLM200 */ + /* NOTE: Message IDs 1000 - 9999 are allocated to the standard widget classes * + * provided with the library with 1000 - 1099 for widget class 0, 1100 - 1199 * + * for widget class 1, etc. Message IDs 10,000 and beyond are for plugin use. */ + xpMsg_UserStart = 10000, + + +}; +typedef int XPWidgetMessage; + +/*************************************************************************** + * WIDGET CALLBACK FUNCTION + ***************************************************************************/ + +/* + * XPWidgetFunc_t + * + * This function defines your custom widget's behavior. It will be called by + * the widgets library to send messages to your widget. The message and widget + * ID are passed in, as well as two ptr-width signed parameters whose meaning + * varies with the message. Return 1 to indicate that you have processed the + * message, 0 to indicate that you have not. For any message that is not + * understood, return 0. + * + */ +typedef int (* XPWidgetFunc_t)( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgetUtils.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgetUtils.h new file mode 100644 index 0000000..ff757f7 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgetUtils.h @@ -0,0 +1,232 @@ +#ifndef _XPWidgetUtils_h_ +#define _XPWidgetUtils_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPWidgetUtils + ***************************************************************************/ +/* + * ## USAGE NOTES + * + * The XPWidgetUtils library contains useful functions that make writing and + * using widgets less of a pain. + * + * One set of functions are the widget behavior functions. These functions + * each add specific useful behaviors to widgets. They can be used in two + * manners: + * + * 1. You can add a widget behavior function to a widget as a callback proc + * using the XPAddWidgetCallback function. The widget will gain that + * behavior. Remember that the last function you add has highest priority. + * You can use this to change or augment the behavior of an existing + * finished widget. + * 2. You can call a widget function from inside your own widget function. + * This allows you to include useful behaviors in custom-built widgets. A + * number of the standard widgets get their behavior from this library. To + * do this, call the behavior function from your function first. If it + * returns 1, that means it handled the event and you don't need to; simply + * return 1. + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * GENERAL UTILITIES + ***************************************************************************/ + + + +/* + * Convenience accessors + * + * It can be clumsy accessing the variables passed in by pointer to a struct + * for mouse and reshape messages; these accessors let you simply pass in the param + * right from the arguments of your widget proc and get back the value you want. + * + */ +#define MOUSE_X(param) (((XPMouseState_t *) (param))->x) +#define MOUSE_Y(param) (((XPMouseState_t *) (param))->y) + +#define DELTA_X(param) (((XPWidgetGeometryChange_t *) (param))->dx) +#define DELTA_Y(param) (((XPWidgetGeometryChange_t *) (param))->dy) +#define DELTA_W(param) (((XPWidgetGeometryChange_t *) (param))->dwidth) +#define DELTA_H(param) (((XPWidgetGeometryChange_t *) (param))->dheight) + +#define KEY_CHAR(param) (((XPKeyState_t *) (param))->key) +#define KEY_FLAGS(param) (((XPKeyState_t *) (param))->flags) +#define KEY_VKEY(param) (((XPKeyState_t *) (param))->vkey) + +#define IN_RECT(x, y, l, t, r, b) \ + (((x) >= (l)) && ((x) <= (r)) && ((y) >= (b)) && ((y) <= (t))) + +/* + * XPWidgetCreate_t + * + * This structure contains all of the parameters needed to create a wiget. It + * is used with XPUCreateWidgets to create widgets in bulk from an array. All + * parameters correspond to those of XPCreateWidget except for the container + * index. + * + * If the container index is equal to the index of a widget in the array, the + * widget in the array passed to XPUCreateWidgets is used as the parent of + * this widget. Note that if you pass an index greater than your own position + * in the array, the parent you are requesting will not exist yet. + * + * If the container index is NO_PARENT, the parent widget is specified as + * NULL. If the container index is PARAM_PARENT, the widget passed into + * XPUCreateWidgets is used. + * + */ +typedef struct { + int left; + int top; + int right; + int bottom; + int visible; + const char * descriptor; + /* Whether ethis widget is a root wiget */ + int isRoot; + /* The index of the widget to contain within, or a constant */ + int containerIndex; + XPWidgetClass widgetClass; +} XPWidgetCreate_t; + +#define NO_PARENT -1 + +#define PARAM_PARENT -2 + +#define WIDGET_COUNT(x) ((sizeof(x) / sizeof(XPWidgetCreate_t))) + +/* + * XPUCreateWidgets + * + * This function creates a series of widgets from a table (see + * XPCreateWidget_t above). Pass in an array of widget creation structures and + * an array of widget IDs that will receive each widget. + * + * Widget parents are specified by index into the created widget table, + * allowing you to create nested widget structures. You can create multiple + * widget trees in one table. Generally you should create widget trees from + * the top down. + * + * You can also pass in a widget ID that will be used when the widget's parent + * is listed as PARAM_PARENT; this allows you to embed widgets created with + * XPUCreateWidgets in a widget created previously. + * + */ +WIDGET_API void XPUCreateWidgets( + const XPWidgetCreate_t * inWidgetDefs, + int inCount, + XPWidgetID inParamParent, + XPWidgetID * ioWidgets); + +/* + * XPUMoveWidgetBy + * + * Simply moves a widget by an amount, +x = right, +y=up, without resizing the + * widget. + * + */ +WIDGET_API void XPUMoveWidgetBy( + XPWidgetID inWidget, + int inDeltaX, + int inDeltaY); + +/*************************************************************************** + * LAYOUT MANAGERS + ***************************************************************************/ +/* + * The layout managers are widget behavior functions for handling where + * widgets move. Layout managers can be called from a widget function or + * attached to a widget later. + * + */ + + +/* + * XPUFixedLayout + * + * This function causes the widget to maintain its children in fixed position + * relative to itself as it is resized. Use this on the top level 'window' + * widget for your window. + * + */ +WIDGET_API int XPUFixedLayout( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +/*************************************************************************** + * WIDGET PROC BEHAVIORS + ***************************************************************************/ +/* + * These widget behavior functions add other useful behaviors to widgets. + * These functions cannot be attached to a widget; they must be called from + * your widget function. + * + */ + + +/* + * XPUSelectIfNeeded + * + * This causes the widget to bring its window to the foreground if it is not + * already. inEatClick specifies whether clicks in the background should be + * consumed by bringin the window to the foreground. + * + */ +WIDGET_API int XPUSelectIfNeeded( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inEatClick); + +/* + * XPUDefocusKeyboard + * + * This causes a click in the widget to send keyboard focus back to X-Plane. + * This stops editing of any text fields, etc. + * + */ +WIDGET_API int XPUDefocusKeyboard( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inEatClick); + +/* + * XPUDragWidget + * + * XPUDragWidget drags the widget in response to mouse clicks. Pass in not + * only the event, but the global coordinates of the drag region, which might + * be a sub-region of your widget (for example, a title bar). + * + */ +WIDGET_API int XPUDragWidget( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inLeft, + int inTop, + int inRight, + int inBottom); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgets.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgets.h new file mode 100644 index 0000000..f4423e2 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Widgets/XPWidgets.h @@ -0,0 +1,538 @@ +#ifndef _XPWidgets_h_ +#define _XPWidgets_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPWidgets + ***************************************************************************/ +/* + * ## THEORY OF OPERATION AND NOTES + * + * Widgets are persistent view 'objects' for X-Plane. A widget is an object + * referenced by its opaque handle (widget ID) and the APIs in this file. You + * cannot access the widget's guts directly. Every Widget has the following + * intrinsic data: + * + * - A bounding box defined in global screen coordinates with 0,0 in the + * bottom left and +y = up, +x = right. + * - A visible box, which is the intersection of the bounding box with the + * widget's parents visible box. + * - Zero or one parent widgets. (Always zero if the widget is a root widget. + * - Zero or more child widgets. + * - Whether the widget is a root. Root widgets are the top level plugin + * windows. + * - Whether the widget is visible. + * - A text string descriptor, whose meaning varies from widget to widget. + * - An arbitrary set of 32 bit integral properties defined by 32-bit integral + * keys. This is how specific widgets store specific data. + * - A list of widget callbacks proc that implements the widgets behaviors. + * + * The Widgets library sends messages to widgets to request specific behaviors + * or notify the widget of things. + * + * Widgets may have more than one callback function, in which case messages + * are sent to the most recently added callback function until the message is + * handled. Messages may also be sent to parents or children; see the + * XPWidgetDefs.h header file for the different widget message dispatching + * functions. By adding a callback function to a window you can 'subclass' its + * behavior. + * + * A set of standard widgets are provided that serve common UI purposes. You + * can also customize or implement entirely custom widgets. + * + * Widgets are different than other view hierarchies (most notably Win32, + * which they bear a striking resemblance to) in the following ways: + * + * - Not all behavior can be patched. State that is managed by the XPWidgets + * DLL and not by individual widgets cannot be customized. + * - All coordinates are in global screen coordinates. Coordinates are not + * relative to an enclosing widget, nor are they relative to a display + * window. + * - Widget messages are always dispatched synchronously, and there is no + * concept of scheduling an update or a dirty region. Messages originate + * from X-Plane as the sim cycle goes by. Since X-Plane is constantly + * redrawing, so are widgets; there is no need to mark a part of a widget as + * 'needing redrawing' because redrawing happens frequently whether the + * widget needs it or not. + * - Any widget may be a 'root' widget, causing it to be drawn; there is no + * relationship between widget class and rootness. Root widgets are + * imlemented as XPLMDisply windows. + * + */ + +#include "XPWidgetDefs.h" +#include "XPLMDisplay.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * WIDGET CREATION AND MANAGEMENT + ***************************************************************************/ + +/* + * XPCreateWidget + * + * This function creates a new widget and returns the new widget's ID to you. + * If the widget creation fails for some reason, it returns NULL. Widget + * creation will fail either if you pass a bad class ID or if there is not + * adequate memory. + * + * Input Parameters: + * + * - Top, left, bottom, and right in global screen coordinates defining the + * widget's location on the screen. + * - inVisible is 1 if the widget should be drawn, 0 to start the widget as + * hidden. + * - inDescriptor is a null terminated string that will become the widget's + * descriptor. + * - inIsRoot is 1 if this is going to be a root widget, 0 if it will not be. + * - inContainer is the ID of this widget's container. It must be 0 for a root + * widget. for a non-root widget, pass the widget ID of the widget to place + * this widget within. If this widget is not going to start inside another + * widget, pass 0; this new widget will then just be floating off in space + * (and will not be drawn until it is placed in a widget. + * - inClass is the class of the widget to draw. Use one of the predefined + * class-IDs to create a standard widget. + * + * A note on widget embedding: a widget is only called (and will be drawn, + * etc.) if it is placed within a widget that will be called. Root widgets are + * always called. So it is possible to have whole chains of widgets that are + * simply not called. You can preconstruct widget trees and then place them + * into root widgets later to activate them if you wish. + * + */ +WIDGET_API XPWidgetID XPCreateWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inVisible, + const char * inDescriptor, + int inIsRoot, + XPWidgetID inContainer, + XPWidgetClass inClass); + +/* + * XPCreateCustomWidget + * + * This function is the same as XPCreateWidget except that instead of passing + * a class ID, you pass your widget callback function pointer defining the + * widget. Use this function to define a custom widget. All parameters are the + * same as XPCreateWidget, except that the widget class has been replaced with + * the widget function. + * + */ +WIDGET_API XPWidgetID XPCreateCustomWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inVisible, + const char * inDescriptor, + int inIsRoot, + XPWidgetID inContainer, + XPWidgetFunc_t inCallback); + +/* + * XPDestroyWidget + * + * This class destroys a widget. Pass in the ID of the widget to kill. If you + * pass 1 for inDestroyChilren, the widget's children will be destroyed first, + * then this widget will be destroyed. (Furthermore, the widget's children + * will be destroyed with the inDestroyChildren flag set to 1, so the + * destruction will recurse down the widget tree.) If you pass 0 for this + * flag, the child widgets will simply end up with their parent set to 0. + * + */ +WIDGET_API void XPDestroyWidget( + XPWidgetID inWidget, + int inDestroyChildren); + +/* + * XPSendMessageToWidget + * + * This sends any message to a widget. You should probably not go around + * simulating the predefined messages that the widgets library defines for + * you. You may however define custom messages for your widgets and send them + * with this method. + * + * This method supports several dispatching patterns; see XPDispatchMode for + * more info. The function returns 1 if the message was handled, 0 if it was + * not. + * + * For each widget that receives the message (see the dispatching modes), each + * widget function from the most recently installed to the oldest one receives + * the message in order until it is handled. + * + */ +WIDGET_API int XPSendMessageToWidget( + XPWidgetID inWidget, + XPWidgetMessage inMessage, + XPDispatchMode inMode, + intptr_t inParam1, + intptr_t inParam2); + +/*************************************************************************** + * WIDGET POSITIONING AND VISIBILITY + ***************************************************************************/ + +/* + * XPPlaceWidgetWithin + * + * This function changes which container a widget resides in. You may NOT use + * this function on a root widget! inSubWidget is the widget that will be + * moved. Pass a widget ID in inContainer to make inSubWidget be a child of + * inContainer. It will become the last/closest widget in the container. Pass + * 0 to remove the widget from any container. Any call to this other than + * passing the widget ID of the old parent of the affected widget will cause + * the widget to be removed from its old parent. Placing a widget within its + * own parent simply makes it the last widget. + * + * NOTE: this routine does not reposition the sub widget in global + * coordinates. If the container has layout management code, it will + * reposition the subwidget for you, otherwise you must do it with + * SetWidgetGeometry. + * + */ +WIDGET_API void XPPlaceWidgetWithin( + XPWidgetID inSubWidget, + XPWidgetID inContainer); + +/* + * XPCountChildWidgets + * + * This routine returns the number of widgets another widget contains. + * + */ +WIDGET_API int XPCountChildWidgets( + XPWidgetID inWidget); + +/* + * XPGetNthChildWidget + * + * This routine returns the widget ID of a child widget by index. Indexes are + * 0 based, from 0 to one minus the number of widgets in the parent, + * inclusive. If the index is invalid, 0 is returned. + * + */ +WIDGET_API XPWidgetID XPGetNthChildWidget( + XPWidgetID inWidget, + int inIndex); + +/* + * XPGetParentWidget + * + * Returns the parent of a widget, or 0 if the widget has no parent. Root + * widgets never have parents and therefore always return 0. + * + */ +WIDGET_API XPWidgetID XPGetParentWidget( + XPWidgetID inWidget); + +/* + * XPShowWidget + * + * This routine makes a widget visible if it is not already. Note that if a + * widget is not in a rooted widget hierarchy or one of its parents is not + * visible, it will still not be visible to the user. + * + */ +WIDGET_API void XPShowWidget( + XPWidgetID inWidget); + +/* + * XPHideWidget + * + * Makes a widget invisible. See XPShowWidget for considerations of when a + * widget might not be visible despite its own visibility state. + * + */ +WIDGET_API void XPHideWidget( + XPWidgetID inWidget); + +/* + * XPIsWidgetVisible + * + * This returns 1 if a widget is visible, 0 if it is not. Note that this + * routine takes into consideration whether a parent is invisible. Use this + * routine to tell if the user can see the widget. + * + */ +WIDGET_API int XPIsWidgetVisible( + XPWidgetID inWidget); + +/* + * XPFindRootWidget + * + * Returns the Widget ID of the root widget that contains the passed in widget + * or NULL if the passed in widget is not in a rooted hierarchy. + * + */ +WIDGET_API XPWidgetID XPFindRootWidget( + XPWidgetID inWidget); + +/* + * XPBringRootWidgetToFront + * + * This routine makes the specified widget be in the front most widget + * hierarchy. If this widget is a root widget, its widget hierarchy comes to + * front, otherwise the widget's root is brought to the front. If this widget + * is not in an active widget hiearchy (e.g. there is no root widget at the + * top of the tree), this routine does nothing. + * + */ +WIDGET_API void XPBringRootWidgetToFront( + XPWidgetID inWidget); + +/* + * XPIsWidgetInFront + * + * This routine returns true if this widget's hierarchy is the front most + * hierarchy. It returns false if the widget's hierarchy is not in front, or + * if the widget is not in a rooted hierarchy. + * + */ +WIDGET_API int XPIsWidgetInFront( + XPWidgetID inWidget); + +/* + * XPGetWidgetGeometry + * + * This routine returns the bounding box of a widget in global coordinates. + * Pass NULL for any parameter you are not interested in. + * + */ +WIDGET_API void XPGetWidgetGeometry( + XPWidgetID inWidget, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/* + * XPSetWidgetGeometry + * + * This function changes the bounding box of a widget. + * + */ +WIDGET_API void XPSetWidgetGeometry( + XPWidgetID inWidget, + int inLeft, + int inTop, + int inRight, + int inBottom); + +/* + * XPGetWidgetForLocation + * + * Given a widget and a location, this routine returns the widget ID of the + * child of that widget that owns that location. If inRecursive is true then + * this will return a child of a child of a widget as it tries to find the + * deepest widget at that location. If inVisibleOnly is true, then only + * visible widgets are considered, otherwise all widgets are considered. The + * widget ID passed for inContainer will be returned if the location is in + * that widget but not in a child widget. 0 is returned if the location is not + * in the container. + * + * NOTE: if a widget's geometry extends outside its parents geometry, it will + * not be returned by this call for mouse locations outside the parent + * geometry. The parent geometry limits the child's eligibility for mouse + * location. + * + */ +WIDGET_API XPWidgetID XPGetWidgetForLocation( + XPWidgetID inContainer, + int inXOffset, + int inYOffset, + int inRecursive, + int inVisibleOnly); + +/* + * XPGetWidgetExposedGeometry + * + * This routine returns the bounds of the area of a widget that is completely + * within its parent widgets. Since a widget's bounding box can be outside its + * parent, part of its area will not be elligible for mouse clicks and should + * not draw. Use XPGetWidgetGeometry to find out what area defines your + * widget's shape, but use this routine to find out what area to actually draw + * into. Note that the widget library does not use OpenGL clipping to keep + * frame rates up, although you could use it internally. + * + */ +WIDGET_API void XPGetWidgetExposedGeometry( + XPWidgetID inWidgetID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/*************************************************************************** + * ACCESSING WIDGET DATA + ***************************************************************************/ + +/* + * XPSetWidgetDescriptor + * + * Every widget has a descriptor, which is a text string. What the text string + * is used for varies from widget to widget; for example, a push button's text + * is its descriptor, a caption shows its descriptor, and a text field's + * descriptor is the text being edited. In other words, the usage for the text + * varies from widget to widget, but this API provides a universal and + * convenient way to get at it. While not all UI widgets need their + * descriptor, many do. + * + */ +WIDGET_API void XPSetWidgetDescriptor( + XPWidgetID inWidget, + const char * inDescriptor); + +/* + * XPGetWidgetDescriptor + * + * This routine returns the widget's descriptor. Pass in the length of the + * buffer you are going to receive the descriptor in. The descriptor will be + * null terminated for you. This routine returns the length of the actual + * descriptor; if you pass NULL for outDescriptor, you can get the + * descriptor's length without getting its text. If the length of the + * descriptor exceeds your buffer length, the buffer will not be null + * terminated (this routine has 'strncpy' semantics). + * + */ +WIDGET_API int XPGetWidgetDescriptor( + XPWidgetID inWidget, + char * outDescriptor, + int inMaxDescLength); + +/* + * XPGetWidgetUnderlyingWindow + * + * Returns the window (from the XPLMDisplay API) that backs your widget + * window. If you have opted in to modern windows, via a call to + * XPLMEnableFeature("XPLM_USE_NATIVE_WIDGET_WINDOWS", 1), you can use the + * returned window ID for display APIs like XPLMSetWindowPositioningMode(), + * allowing you to pop the widget window out into a real OS window, or move it + * into VR. + * + */ +WIDGET_API XPLMWindowID XPGetWidgetUnderlyingWindow( + XPWidgetID inWidget); + +/* + * XPSetWidgetProperty + * + * This function sets a widget's property. Properties are arbitrary values + * associated by a widget by ID. + * + */ +WIDGET_API void XPSetWidgetProperty( + XPWidgetID inWidget, + XPWidgetPropertyID inProperty, + intptr_t inValue); + +/* + * XPGetWidgetProperty + * + * This routine returns the value of a widget's property, or 0 if the property + * is not defined. If you need to know whether the property is defined, pass a + * pointer to an int for inExists; the existence of that property will be + * returned in the int. Pass NULL for inExists if you do not need this + * information. + * + */ +WIDGET_API intptr_t XPGetWidgetProperty( + XPWidgetID inWidget, + XPWidgetPropertyID inProperty, + int * inExists); /* Can be NULL */ + +/*************************************************************************** + * KEYBOARD MANAGEMENT + ***************************************************************************/ + +/* + * XPSetKeyboardFocus + * + * Controls which widget will receive keystrokes. Pass the widget ID of the + * widget to get the keys. Note that if the widget does not care about + * keystrokes, they will go to the parent widget, and if no widget cares about + * them, they go to X-Plane. + * + * If you set the keyboard focus to widget ID 0, X-Plane gets keyboard focus. + * + * This routine returns the widget ID that ended up with keyboard focus, or 0 + * for X-Plane. + * + * Keyboard focus is not changed if the new widget will not accept it. For + * setting to X-Plane, keyboard focus is always accepted. + * + */ +WIDGET_API XPWidgetID XPSetKeyboardFocus( + XPWidgetID inWidget); + +/* + * XPLoseKeyboardFocus + * + * This causes the specified widget to lose focus; focus is passed to its + * parent, or the next parent that will accept it. This routine does nothing + * if this widget does not have focus. + * + */ +WIDGET_API void XPLoseKeyboardFocus( + XPWidgetID inWidget); + +/* + * XPGetWidgetWithFocus + * + * This routine returns the widget that has keyboard focus, or 0 if X-Plane + * has keyboard focus or some other plugin window that does not have widgets + * has focus. + * + */ +WIDGET_API XPWidgetID XPGetWidgetWithFocus(void); + +/*************************************************************************** + * CREATING CUSTOM WIDGETS + ***************************************************************************/ + +/* + * XPAddWidgetCallback + * + * This function adds a new widget callback to a widget. This widget callback + * supercedes any existing ones and will receive messages first; if it does + * not handle messages they will go on to be handled by pre-existing widgets. + * + * The widget function will remain on the widget for the life of the widget. + * The creation message will be sent to the new callback immediately with the + * widget ID, and the destruction message will be sent before the other widget + * function receives a destruction message. + * + * This provides a way to 'subclass' an existing widget. By providing a second + * hook that only handles certain widget messages, you can customize or extend + * widget behavior. + * + */ +WIDGET_API void XPAddWidgetCallback( + XPWidgetID inWidget, + XPWidgetFunc_t inNewCallback); + +/* + * XPGetWidgetClassFunc + * + * Given a widget class, this function returns the callbacks that power that + * widget class. + * + */ +WIDGET_API XPWidgetFunc_t XPGetWidgetClassFunc( + XPWidgetClass inWidgetClass); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp new file mode 100644 index 0000000..5fe6218 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCBroadcaster.cpp @@ -0,0 +1,56 @@ +#include "XPCBroadcaster.h" +#include "XPCListener.h" + +XPCBroadcaster::XPCBroadcaster() : + mIterator(NULL) +{ +} + +XPCBroadcaster::~XPCBroadcaster() +{ + ListenerVector::iterator iter; + mIterator = &iter; + for (iter = mListeners.begin(); iter != mListeners.end(); ++iter) + { + (*iter)->BroadcasterRemoved(this); + } +} + +void XPCBroadcaster::AddListener( + XPCListener * inListener) +{ + mListeners.push_back(inListener); + inListener->BroadcasterAdded(this); +} + +void XPCBroadcaster::RemoveListener( + XPCListener * inListener) +{ + ListenerVector::iterator iter = std::find + (mListeners.begin(), mListeners.end(), inListener); + if (iter == mListeners.end()) + return; + + if (mIterator != NULL) + { + if (*mIterator >= iter) + (*mIterator)--; + } + + mListeners.erase(iter); + inListener->BroadcasterRemoved(this); +} + +void XPCBroadcaster::BroadcastMessage( + int inMessage, + void * inParam) +{ + ListenerVector::iterator iter; + mIterator = &iter; + for (iter = mListeners.begin(); iter != mListeners.end(); ++iter) + { + (*iter)->ListenToMessage(inMessage, inParam); + } + mIterator = NULL; +} + diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCBroadcaster.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCBroadcaster.h new file mode 100644 index 0000000..8f34a05 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCBroadcaster.h @@ -0,0 +1,38 @@ +#ifndef _XPCBroadcaster_h_ +#define _XPCBroadcaster_h_ + +#include +#include + +class XPCListener; + +class XPCBroadcaster { +public: + + XPCBroadcaster(); + virtual ~XPCBroadcaster(); + + void AddListener( + XPCListener * inListener); + void RemoveListener( + XPCListener * inListener); + +protected: + + void BroadcastMessage( + int inMessage, + void * inParam=0); + +private: + + typedef std::vector ListenerVector; + + ListenerVector mListeners; + + // Reentrancy support + + ListenerVector::iterator * mIterator; + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCDisplay.cpp b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCDisplay.cpp new file mode 100644 index 0000000..fc996ca --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCDisplay.cpp @@ -0,0 +1,104 @@ +#include "XPCDisplay.h" + +XPCKeySniffer::XPCKeySniffer(int inBeforeWindows) : mBeforeWindows(inBeforeWindows) +{ + XPLMRegisterKeySniffer(KeySnifferCB, mBeforeWindows, reinterpret_cast(this)); +} + +XPCKeySniffer::~XPCKeySniffer() +{ + XPLMUnregisterKeySniffer(KeySnifferCB, mBeforeWindows, reinterpret_cast(this)); +} + + +int XPCKeySniffer::KeySnifferCB( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefCon) +{ + XPCKeySniffer * me = reinterpret_cast(inRefCon); + return me->HandleKeyStroke(inCharKey, inFlags, inVirtualKey); +} + +XPCWindow::XPCWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible) +{ + mWindow = XPLMCreateWindow(inLeft, inTop, inRight, inBottom, inIsVisible, + DrawCB, HandleKeyCB, MouseClickCB, + reinterpret_cast(this)); +} + +XPCWindow::~XPCWindow() +{ + XPLMDestroyWindow(mWindow); +} + +void XPCWindow::GetWindowGeometry( + int * outLeft, + int * outTop, + int * outRight, + int * outBottom) +{ + XPLMGetWindowGeometry(mWindow, outLeft, outTop, outRight, outBottom); +} + +void XPCWindow::SetWindowGeometry( + int inLeft, + int inTop, + int inRight, + int inBottom) +{ + XPLMSetWindowGeometry(mWindow, inLeft, inTop, inRight, inBottom); +} + +int XPCWindow::GetWindowIsVisible(void) +{ + return XPLMGetWindowIsVisible(mWindow); +} + +void XPCWindow::SetWindowIsVisible( + int inIsVisible) +{ + XPLMSetWindowIsVisible(mWindow, inIsVisible); +} + +void XPCWindow::TakeKeyboardFocus(void) +{ + XPLMTakeKeyboardFocus(mWindow); +} + +void XPCWindow::BringWindowToFront(void) +{ + XPLMBringWindowToFront(mWindow); +} + +int XPCWindow::IsWindowInFront(void) +{ + return XPLMIsWindowInFront(mWindow); +} + +void XPCWindow::DrawCB(XPLMWindowID inWindowID, void * inRefcon) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + me->DoDraw(); +} + +void XPCWindow::HandleKeyCB(XPLMWindowID inWindowID, char inKey, XPLMKeyFlags inFlags, char inVirtualKey, void * inRefcon, int losingFocus) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + if (losingFocus) + me->LoseFocus(); + else + me->HandleKey(inKey, inFlags, inVirtualKey); +} + +int XPCWindow::MouseClickCB(XPLMWindowID inWindowID, int x, int y, XPLMMouseStatus inMouse, void * inRefcon) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + return me->HandleClick(x, y, inMouse); +} diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCDisplay.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCDisplay.h new file mode 100644 index 0000000..2465928 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCDisplay.h @@ -0,0 +1,73 @@ +#ifndef _XPCDisplay_h_ +#define _XPCDisplay_h_ + +#include "XPLMDisplay.h" + +class XPCKeySniffer { +public: + + XPCKeySniffer(int inBeforeWindows); + virtual ~XPCKeySniffer(); + + virtual int HandleKeyStroke( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey)=0; + +private: + + int mBeforeWindows; + + static int KeySnifferCB( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefCon); +}; + + + +class XPCWindow { +public: + + XPCWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible); + virtual ~XPCWindow(); + + virtual void DoDraw(void)=0; + virtual void HandleKey(char inKey, XPLMKeyFlags inFlags, char inVirtualKey)=0; + virtual void LoseFocus(void)=0; + virtual int HandleClick(int x, int y, XPLMMouseStatus inMouse)=0; + + void GetWindowGeometry( + int * outLeft, + int * outTop, + int * outRight, + int * outBottom); + void SetWindowGeometry( + int inLeft, + int inTop, + int inRight, + int inBottom); + int GetWindowIsVisible(void); + void SetWindowIsVisible( + int inIsVisible); + void TakeKeyboardFocus(void); + void BringWindowToFront(void); + int IsWindowInFront(void); + +private: + + XPLMWindowID mWindow; + + static void DrawCB(XPLMWindowID inWindowID, void * inRefcon); + static void HandleKeyCB(XPLMWindowID inWindowID, char inKey, XPLMKeyFlags inFlags, char inVirtualKey, void * inRefcon, int losingFocus); + static int MouseClickCB(XPLMWindowID inWindowID, int x, int y, XPLMMouseStatus inMouse, void * inRefcon); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCListener.cpp b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCListener.cpp new file mode 100644 index 0000000..b4c77aa --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCListener.cpp @@ -0,0 +1,27 @@ +#include "XPCListener.h" +#include "XPCBroadcaster.h" + +XPCListener::XPCListener() +{ +} + +XPCListener::~XPCListener() +{ + while (!mBroadcasters.empty()) + mBroadcasters.front()->RemoveListener(this); +} + +void XPCListener::BroadcasterAdded( + XPCBroadcaster * inBroadcaster) +{ + mBroadcasters.push_back(inBroadcaster); +} + +void XPCListener::BroadcasterRemoved( + XPCBroadcaster * inBroadcaster) +{ + BroadcastVector::iterator iter = std::find(mBroadcasters.begin(), + mBroadcasters.end(), inBroadcaster); + if (iter != mBroadcasters.end()) + mBroadcasters.erase(iter); +} diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCListener.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCListener.h new file mode 100644 index 0000000..dbdd2a0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCListener.h @@ -0,0 +1,36 @@ +#ifndef _XPCListener_h_ +#define _XPCListener_h_ + +#include +#include + +class XPCBroadcaster; + + +class XPCListener { +public: + + XPCListener(); + virtual ~XPCListener(); + + virtual void ListenToMessage( + int inMessage, + void * inParam)=0; + +private: + + typedef std::vector BroadcastVector; + + BroadcastVector mBroadcasters; + + friend class XPCBroadcaster; + + void BroadcasterAdded( + XPCBroadcaster * inBroadcaster); + + void BroadcasterRemoved( + XPCBroadcaster * inBroadcaster); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCProcessing.cpp b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCProcessing.cpp new file mode 100644 index 0000000..352c05f --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCProcessing.cpp @@ -0,0 +1,52 @@ +#include "XPCProcessing.h" +#include "XPLMUtilities.h" + +XPCProcess::XPCProcess() : + mInCallback(false), + mCallbackTime(0) +{ + XPLMRegisterFlightLoopCallback(FlightLoopCB, 0, reinterpret_cast(this)); +} + +XPCProcess::~XPCProcess() +{ + XPLMUnregisterFlightLoopCallback(FlightLoopCB, reinterpret_cast(this)); +} + +void XPCProcess::StartProcessTime(float inSeconds) +{ + mCallbackTime = inSeconds; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + +void XPCProcess::StartProcessCycles(int inCycles) +{ + mCallbackTime = -inCycles; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + +void XPCProcess::StopProcess(void) +{ + mCallbackTime = 0; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + + +float XPCProcess::FlightLoopCB( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon) +{ + XPCProcess * me = reinterpret_cast(inRefcon); + me->mInCallback = true; + me->DoProcessing(inElapsedSinceLastCall, inElapsedTimeSinceLastFlightLoop, inCounter); + me->mInCallback = false; + return me->mCallbackTime; +} \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCProcessing.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCProcessing.h new file mode 100644 index 0000000..cd735e5 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCProcessing.h @@ -0,0 +1,37 @@ +#ifndef _XPCProcessing_h_ +#define _XPCProcessing_h_ + +#include "XPLMProcessing.h" + +class XPCProcess { +public: + + XPCProcess(); + virtual ~XPCProcess(); + + void StartProcessTime(float inSeconds); + void StartProcessCycles(int inCycles); + void StopProcess(void); + + virtual void DoProcessing( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter)=0; + +private: + + static float FlightLoopCB( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon); + + bool mInCallback; + float mCallbackTime; + + XPCProcess(const XPCProcess&); + XPCProcess& operator=(const XPCProcess&); + +}; + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidget.cpp b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidget.cpp new file mode 100644 index 0000000..8ef8aa3 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidget.cpp @@ -0,0 +1,123 @@ +#include "XPCWidget.h" + +XPCWidget::XPCWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + bool inVisible, + const char * inDescriptor, + bool inIsRoot, + XPWidgetID inParent, + XPWidgetClass inClass) : + mWidget(NULL), + mOwnsChildren(false), + mOwnsWidget(true) +{ + mWidget = XPCreateWidget( + inLeft, inTop, inRight, inBottom, + inVisible ? 1 : 0, + inDescriptor, + inIsRoot ? 1 : 0, + inIsRoot ? NULL : inParent, + inClass); + + XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); + XPAddWidgetCallback(mWidget, WidgetCallback); +} + +XPCWidget::XPCWidget( + XPWidgetID inWidget, + bool inOwnsWidget) : + mWidget(inWidget), + mOwnsChildren(false), + mOwnsWidget(inOwnsWidget) +{ + XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); + XPAddWidgetCallback(mWidget, WidgetCallback); +} + +XPCWidget::~XPCWidget() +{ + if (mOwnsWidget) + XPDestroyWidget(mWidget, mOwnsChildren ? 1 : 0); +} + +void XPCWidget::SetOwnsWidget( + bool inOwnsWidget) +{ + mOwnsWidget = inOwnsWidget; +} + +void XPCWidget::SetOwnsChildren( + bool inOwnsChildren) +{ + mOwnsChildren = inOwnsChildren; +} + +XPCWidget::operator XPWidgetID () const +{ + return mWidget; +} + +XPWidgetID XPCWidget::Get(void) const +{ + return mWidget; +} + +void XPCWidget::AddAttachment( + XPCWidgetAttachment * inAttachment, + bool inOwnsAttachment, + bool inPrefilter) +{ + if (inPrefilter) + { + mAttachments.insert(mAttachments.begin(), AttachmentInfo(inAttachment, inOwnsAttachment)); + } else { + mAttachments.push_back(AttachmentInfo(inAttachment, inOwnsAttachment)); + } +} + +void XPCWidget::RemoveAttachment( + XPCWidgetAttachment * inAttachment) +{ + for (AttachmentVector::iterator iter = mAttachments.begin(); + iter != mAttachments.end(); ++iter) + { + if (iter->first == inAttachment) + { + mAttachments.erase(iter); + return; + } + } +} + +int XPCWidget::HandleWidgetMessage( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + return 0; +} + +int XPCWidget::WidgetCallback( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + XPCWidget * me = reinterpret_cast(XPGetWidgetProperty(inWidget, xpProperty_Object, NULL)); + if (me == NULL) + return 0; + + for (AttachmentVector::iterator iter = me->mAttachments.begin(); iter != + me->mAttachments.end(); ++iter) + { + int result = iter->first->HandleWidgetMessage(me, inMessage, inWidget, inParam1, inParam2); + if (result != 0) + return result; + } + + return me->HandleWidgetMessage(inMessage, inWidget, inParam1, inParam2); +} diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidget.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidget.h new file mode 100644 index 0000000..788b56a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidget.h @@ -0,0 +1,84 @@ +#ifndef _XPCWidget_h_ +#define _XPCWidget_h_ + +#include +#include +#include "XPWidgets.h" + +class XPCWidget; + +class XPCWidgetAttachment { +public: + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2)=0; + +}; + +class XPCWidget { +public: + + XPCWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + bool inVisible, + const char * inDescriptor, + bool inIsRoot, + XPWidgetID inParent, + XPWidgetClass inClass); + XPCWidget( + XPWidgetID inWidget, + bool inOwnsWidget); + virtual ~XPCWidget(); + + void SetOwnsWidget( + bool inOwnsWidget); + void SetOwnsChildren( + bool inOwnsChildren); + + operator XPWidgetID () const; + + XPWidgetID Get(void) const; + + void AddAttachment( + XPCWidgetAttachment * inAttachment, + bool inOwnsAttachment, + bool inPrefilter); + void RemoveAttachment( + XPCWidgetAttachment * inAttachment); + + virtual int HandleWidgetMessage( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + static int WidgetCallback( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + + typedef std::pair AttachmentInfo; + typedef std::vector AttachmentVector; + + AttachmentVector mAttachments; + XPWidgetID mWidget; + bool mOwnsChildren; + bool mOwnsWidget; + + XPCWidget(); + XPCWidget(const XPCWidget&); + XPCWidget& operator=(const XPCWidget&); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp new file mode 100644 index 0000000..d87f105 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidgetAttachments.cpp @@ -0,0 +1,267 @@ +#include "XPCWidgetAttachments.h" +#include "XPStandardWidgets.h" +#include "XPWidgetUtils.h" + +static void XPCGetOrderedSubWidgets( + XPWidgetID inWidget, + std::vector& outChildren); + +XPCKeyFilterAttachment::XPCKeyFilterAttachment( + const char * inValidKeys, + const char * outValidKeys) : + mInput(inValidKeys), + mOutput(outValidKeys) +{ +} + +XPCKeyFilterAttachment::~XPCKeyFilterAttachment() +{ +} + +int XPCKeyFilterAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if (inMessage == xpMsg_KeyPress) + { + char& theKey = KEY_CHAR(inParam1); + std::string::size_type pos = mInput.find(theKey); + if (pos == std::string::npos) + return 1; // Not found; eat the key! + else { + theKey = mOutput[pos]; + return 0; + } // Let it live. + } + return 0; +} + + +XPCKeyMessageAttachment::XPCKeyMessageAttachment( + char inKey, + int inMessage, + void * inParam, + bool inConsume, + bool inVkey, + XPCListener * inListener) : + mKey(inKey), mMsg(inMessage), mParam(inParam), mConsume(inConsume), + mVkey(inVkey) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCKeyMessageAttachment::~XPCKeyMessageAttachment() +{ +} + +int XPCKeyMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if (inMessage == xpMsg_KeyPress) + { + char theKey = mVkey ? KEY_VKEY(inParam1) : KEY_CHAR(inParam1); + if (theKey != mKey) + return 0; + if (!(KEY_FLAGS(inParam1) & xplm_DownFlag)) + return 0; + + BroadcastMessage(mMsg, mParam); + return mConsume ? 1 : 0; + } + return 0; +} + +XPCPushButtonMessageAttachment::XPCPushButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCPushButtonMessageAttachment::~XPCPushButtonMessageAttachment() +{ +} + +int XPCPushButtonMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_PushButtonPressed) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + if ((inMessage == xpMsg_ButtonStateChanged) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + return 0; +} + +XPCSliderMessageAttachment::XPCSliderMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCSliderMessageAttachment::~XPCSliderMessageAttachment() +{ +} + +int XPCSliderMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_ScrollBarSliderPositionChanged) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + return 0; +} + + +XPCCloseButtonMessageAttachment::XPCCloseButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCCloseButtonMessageAttachment::~XPCCloseButtonMessageAttachment() +{ +} + +int XPCCloseButtonMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMessage_CloseButtonPushed) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + return 0; +} + +XPCTabGroupAttachment::XPCTabGroupAttachment() +{ +} + +XPCTabGroupAttachment::~XPCTabGroupAttachment() +{ +} + +int XPCTabGroupAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_KeyPress) && (KEY_CHAR(inParam1) == XPLM_KEY_TAB) && + ((KEY_FLAGS(inParam1) & xplm_UpFlag) == 0)) + { + bool backwards = (KEY_FLAGS(inParam1) & xplm_ShiftFlag) != 0; + std::vector widgets; + XPCGetOrderedSubWidgets(inWidget, widgets); + int n, index = 0; + XPWidgetID focusWidget = XPGetWidgetWithFocus(); + std::vector::iterator iter = std::find(widgets.begin(), widgets.end(), focusWidget); + if (iter != widgets.end()) + { + index = std::distance(widgets.begin(), iter); + if (backwards) + index--; + else + index++; + if (index < 0) + index = widgets.size() - 1; + if (index >= widgets.size()) + index = 0; + } + + if (backwards) + { + for (n = index; n >= 0; --n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + for (n = widgets.size() - 1; n > index; --n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + } else { + for (n = index; n < widgets.size(); ++n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + for (n = 0; n < index; ++n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + } + } + return 0; +} + + + +static void XPCGetOrderedSubWidgets( + XPWidgetID inWidget, + std::vector& outChildren) +{ + outChildren.clear(); + int count = XPCountChildWidgets(inWidget); + for (int n = 0; n < count; ++n) + { + XPWidgetID child = XPGetNthChildWidget(inWidget, n); + outChildren.push_back(child); + std::vector grandChildren; + XPCGetOrderedSubWidgets(child, grandChildren); + + outChildren.insert(outChildren.end(), grandChildren.begin(), grandChildren.end()); + } +} diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h new file mode 100644 index 0000000..91fb587 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/Wrappers/XPCWidgetAttachments.h @@ -0,0 +1,146 @@ +#ifndef _XPCWidgetAttachments_h_ +#define _XPCWidgetAttachments_h_ + +#include + +#include "XPCWidget.h" +#include "XPCBroadcaster.h" + +class XPCKeyFilterAttachment : public XPCWidgetAttachment { +public: + + XPCKeyFilterAttachment( + const char * inValidKeys, + const char * outValidKeys); + virtual ~XPCKeyFilterAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + std::string mInput; + std::string mOutput; + +}; + + +class XPCKeyMessageAttachment : public XPCWidgetAttachment, public XPCBroadcaster { +public: + + XPCKeyMessageAttachment( + char inKey, + int inMessage, + void * inParam, + bool inConsume, + bool inVkey, + XPCListener * inListener); + virtual ~XPCKeyMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + char mKey; + bool mVkey; + int mMsg; + void * mParam; + bool mConsume; + +}; + +class XPCPushButtonMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCPushButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCPushButtonMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + +class XPCSliderMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCSliderMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCSliderMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + + +class XPCCloseButtonMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCCloseButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCCloseButtonMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + +class XPCTabGroupAttachment : public XPCWidgetAttachment { +public: + + XPCTabGroupAttachment(); + virtual ~XPCTabGroupAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMCamera.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMCamera.h new file mode 100644 index 0000000..db930ef --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMCamera.h @@ -0,0 +1,167 @@ +#ifndef _XPLMCamera_h_ +#define _XPLMCamera_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMCamera + ***************************************************************************/ +/* + * The XPLMCamera APIs allow plug-ins to control the camera angle in X-Plane. + * This has a number of applications, including but not limited to: + * + * - Creating new views (including dynamic/user-controllable views) for the + * user. + * - Creating applications that use X-Plane as a renderer of scenery, + * aircrafts, or both. + * + * The camera is controlled via six parameters: a location in OpenGL + * coordinates and pitch, roll and yaw, similar to an airplane's position. + * OpenGL coordinate info is described in detail in the XPLMGraphics + * documentation; generally you should use the XPLMGraphics routines to + * convert from world to local coordinates. The camera's orientation starts + * facing level with the ground directly up the negative-Z axis (approximately + * north) with the horizon horizontal. It is then rotated clockwise for yaw, + * pitched up for positive pitch, and rolled clockwise around the vector it is + * looking along for roll. + * + * You control the camera either either until the user selects a new view or + * permanently (the later being similar to how UDP camera control works). You + * control the camera by registering a callback per frame from which you + * calculate the new camera positions. This guarantees smooth camera motion. + * + * Use the XPLMDataAccess APIs to get information like the position of the + * aircraft, etc. for complex camera positioning. + * + * Note: if your goal is to move the virtual pilot in the cockpit, this API is + * not needed; simply update the datarefs for the pilot's head position. + * + * For custom exterior cameras, set the camera's mode to an external view + * first to get correct sound and 2-d panel behavior. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * CAMERA CONTROL + ***************************************************************************/ + +/* + * XPLMCameraControlDuration + * + * This enumeration states how long you want to retain control of the camera. + * You can retain it indefinitely or until the user selects a new view. + * + */ +enum { + /* Control the camera until the user picks a new view. */ + xplm_ControlCameraUntilViewChanges = 1, + + /* Control the camera until your plugin is disabled or another plugin forcably* + * takes control. */ + xplm_ControlCameraForever = 2, + + +}; +typedef int XPLMCameraControlDuration; + +/* + * XPLMCameraPosition_t + * + * This structure contains a full specification of the camera. X, Y, and Z are + * the camera's position in OpenGL coordiantes; pitch, roll, and yaw are + * rotations from a camera facing flat north in degrees. Positive pitch means + * nose up, positive roll means roll right, and positive yaw means yaw right, + * all in degrees. Zoom is a zoom factor, with 1.0 meaning normal zoom and 2.0 + * magnifying by 2x (objects appear larger). + * + */ +typedef struct { + float x; + float y; + float z; + float pitch; + float heading; + float roll; + float zoom; +} XPLMCameraPosition_t; + +/* + * XPLMCameraControl_f + * + * You use an XPLMCameraControl function to provide continuous control over + * the camera. You are passed in a structure in which to put the new camera + * position; modify it and return 1 to reposition the camera. Return 0 to + * surrender control of the camera; camera control will be handled by X-Plane + * on this draw loop. The contents of the structure as you are called are + * undefined. + * + * If X-Plane is taking camera control away from you, this function will be + * called with inIsLosingControl set to 1 and ioCameraPosition NULL. + * + */ +typedef int (* XPLMCameraControl_f)( + XPLMCameraPosition_t * outCameraPosition, /* Can be NULL */ + int inIsLosingControl, + void * inRefcon); + +/* + * XPLMControlCamera + * + * This function repositions the camera on the next drawing cycle. You must + * pass a non-null control function. Specify in inHowLong how long you'd like + * control (indefinitely or until a new view mode is set by the user). + * + */ +XPLM_API void XPLMControlCamera( + XPLMCameraControlDuration inHowLong, + XPLMCameraControl_f inControlFunc, + void * inRefcon); + +/* + * XPLMDontControlCamera + * + * This function stops you from controlling the camera. If you have a camera + * control function, it will not be called with an inIsLosingControl flag. + * X-Plane will control the camera on the next cycle. + * + * For maximum compatibility you should not use this routine unless you are in + * posession of the camera. + * + */ +XPLM_API void XPLMDontControlCamera(void); + +/* + * XPLMIsCameraBeingControlled + * + * This routine returns 1 if the camera is being controlled, zero if it is + * not. If it is and you pass in a pointer to a camera control duration, the + * current control duration will be returned. + * + */ +XPLM_API int XPLMIsCameraBeingControlled( + XPLMCameraControlDuration * outCameraControlDuration); /* Can be NULL */ + +/* + * XPLMReadCameraPosition + * + * This function reads the current camera position. + * + */ +XPLM_API void XPLMReadCameraPosition( + XPLMCameraPosition_t * outCameraPosition); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDataAccess.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDataAccess.h new file mode 100644 index 0000000..d8d1418 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDataAccess.h @@ -0,0 +1,716 @@ +#ifndef _XPLMDataAccess_h_ +#define _XPLMDataAccess_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDataAccess + ***************************************************************************/ +/* + * The data access API gives you a generic, flexible, high performance way to + * read and write data to and from X-Plane and other plug-ins. For example, + * this API allows you to read and set the nav radios, get the plane location, + * determine the current effective graphics frame rate, etc. + * + * The data access APIs are the way that you read and write data from the sim + * as well as other plugins. + * + * The API works using opaque data references. A data reference is a source of + * data; you do not know where it comes from, but once you have it you can + * read the data quickly and possibly write it. + * + * Dataref Lookup + * -------------- + * + * Data references are identified by verbose, permanent string names; by + * convention these names use path separates to form a hierarchy of datarefs, + * e.g. (sim/cockpit/radios/nav1_freq_hz). The actual opaque numeric value of + * the data reference, as returned by the XPLM API, is implementation defined + * and changes each time X-Plane is launched; therefore you need to look up + * the dataref by path every time your plugin runs. + * + * The task of looking up a data reference is relatively expensive; look up + * your data references once based on the verbose path strings, and save the + * opaque data reference value for the duration of your plugin's operation. + * Reading and writing data references is relatively fast (the cost is + * equivalent to two function calls through function pointers). + * + * X-Plane publishes over 4000 datarefs; a complete list may be found in the + * reference section of the SDK online documentation (from the SDK home page, + * choose Documentation). + * + * Dataref Types + * ------------- + * + * A note on typing: you must know the correct data type to read and write. + * APIs are provided for reading and writing data in a number of ways. You can + * also double check the data type for a data ref. Automatic type conversion + * is not done for you. + * + * Dataref types are a set, e.g. a dataref can be more than one type. When + * this happens, you can choose which API you want to use to read. For + * example, it is not uncommon for a dataref to be of type float and double. + * This means you can use either XPLMGetDatad or XPLMGetDataf to read it. + * + * Creating New Datarefs + * --------------------- + * + * X-Plane provides datarefs that come with the sim, but plugins can also + * create their own datarefs. A plugin creates a dataref by registering + * function callbacks to read and write the dataref. The XPLM will call your + * plugin each time some other plugin (or X-Plane) tries to read or write the + * dataref. You must provide a read (and optional write) callback for each + * data type you support. + * + * A note for plugins sharing data with other plugins: the load order of + * plugins is not guaranteed. To make sure that every plugin publishing data + * has published their data references before other plugins try to subscribe, + * publish your data references in your start routine but resolve them the + * first time your 'enable' routine is called, or the first time they are + * needed in code. + * + * When a plugin that created a dataref is unloaded, it becomes "orphaned". + * The dataref handle continues to be usable, but the dataref is not writable, + * and reading it will always return 0 (or 0 items for arrays). If the plugin + * is reloaded and re-registers the dataref, the handle becomes un-orphaned + * and works again. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * READING AND WRITING DATA + ***************************************************************************/ +/* + * These routines allow you to access data from within X-Plane and sometimes + * modify it. + * + */ + + +/* + * XPLMDataRef + * + * A data ref is an opaque handle to data provided by the simulator or another + * plugin. It uniquely identifies one variable (or array of variables) over + * the lifetime of your plugin. You never hard code these values; you always + * get them from XPLMFindDataRef. + * + */ +typedef void * XPLMDataRef; + +/* + * XPLMDataTypeID + * + * This is an enumeration that defines the type of the data behind a data + * reference. This allows you to sanity check that the data type matches what + * you expect. But for the most part, you will know the type of data you are + * expecting from the online documentation. + * + * Data types each take a bit field; it is legal to have a single dataref be + * more than one type of data. Whe this happens, you can pick any matching + * get/set API. + * + */ +enum { + /* Data of a type the current XPLM doesn't do. */ + xplmType_Unknown = 0, + + /* A single 4-byte integer, native endian. */ + xplmType_Int = 1, + + /* A single 4-byte float, native endian. */ + xplmType_Float = 2, + + /* A single 8-byte double, native endian. */ + xplmType_Double = 4, + + /* An array of 4-byte floats, native endian. */ + xplmType_FloatArray = 8, + + /* An array of 4-byte integers, native endian. */ + xplmType_IntArray = 16, + + /* A variable block of data. */ + xplmType_Data = 32, + + +}; +typedef int XPLMDataTypeID; + +/* + * XPLMFindDataRef + * + * Given a c-style string that names the data ref, this routine looks up the + * actual opaque XPLMDataRef that you use to read and write the data. The + * string names for datarefs are published on the X-Plane SDK web site. + * + * This function returns NULL if the data ref cannot be found. + * + * NOTE: this function is relatively expensive; save the XPLMDataRef this + * function returns for future use. Do not look up your data ref by string + * every time you need to read or write it. + * + */ +XPLM_API XPLMDataRef XPLMFindDataRef( + const char * inDataRefName); + +/* + * XPLMCanWriteDataRef + * + * Given a data ref, this routine returns true if you can successfully set the + * data, false otherwise. Some datarefs are read-only. + * + * NOTE: even if a dataref is marked writable, it may not act writable. This + * can happen for datarefs that X-Plane writes to on every frame of + * simulation. In some cases, the dataref is writable but you have to set a + * separate "override" dataref to 1 to stop X-Plane from writing it. + * + */ +XPLM_API int XPLMCanWriteDataRef( + XPLMDataRef inDataRef); + +/* + * XPLMIsDataRefGood + * + * This function returns true if the passed in handle is a valid dataref that + * is not orphaned. + * + * Note: there is normally no need to call this function; datarefs returned by + * XPLMFindDataRef remain valid (but possibly orphaned) unless there is a + * complete plugin reload (in which case your plugin is reloaded anyway). + * Orphaned datarefs can be safely read and return 0. Therefore you never need + * to call XPLMIsDataRefGood to 'check' the safety of a dataref. + * (XPLMIsDatarefGood performs some slow checking of the handle validity, so + * it has a perormance cost.) + * + */ +XPLM_API int XPLMIsDataRefGood( + XPLMDataRef inDataRef); + +/* + * XPLMGetDataRefTypes + * + * This routine returns the types of the data ref for accessor use. If a data + * ref is available in multiple data types, the bit-wise OR of these types + * will be returned. + * + */ +XPLM_API XPLMDataTypeID XPLMGetDataRefTypes( + XPLMDataRef inDataRef); + +/*************************************************************************** + * DATA ACCESSORS + ***************************************************************************/ +/* + * These routines read and write the data references. For each supported data + * type there is a reader and a writer. + * + * If the data ref is orphaned or the plugin that provides it is disabled or + * there is a type mismatch, the functions that read data will return 0 as a + * default value or not modify the passed in memory. The plugins that write + * data will not write under these circumstances or if the data ref is + * read-only. + * + * NOTE: to keep the overhead of reading datarefs low, these routines do not + * do full validation of a dataref; passing a junk value for a dataref can + * result in crashing the sim. The get/set APIs do check for NULL. + * + * For array-style datarefs, you specify the number of items to read/write and + * the offset into the array; the actual number of items read or written is + * returned. This may be less to prevent an array-out-of-bounds error. + * + */ + + +/* + * XPLMGetDatai + * + * Read an integer data ref and return its value. The return value is the + * dataref value or 0 if the dataref is NULL or the plugin is disabled. + * + */ +XPLM_API int XPLMGetDatai( + XPLMDataRef inDataRef); + +/* + * XPLMSetDatai + * + * Write a new value to an integer data ref. This routine is a no-op if the + * plugin publishing the dataref is disabled, the dataref is NULL, or the + * dataref is not writable. + * + */ +XPLM_API void XPLMSetDatai( + XPLMDataRef inDataRef, + int inValue); + +/* + * XPLMGetDataf + * + * Read a single precision floating point dataref and return its value. The + * return value is the dataref value or 0.0 if the dataref is NULL or the + * plugin is disabled. + * + */ +XPLM_API float XPLMGetDataf( + XPLMDataRef inDataRef); + +/* + * XPLMSetDataf + * + * Write a new value to a single precision floating point data ref. This + * routine is a no-op if the plugin publishing the dataref is disabled, the + * dataref is NULL, or the dataref is not writable. + * + */ +XPLM_API void XPLMSetDataf( + XPLMDataRef inDataRef, + float inValue); + +/* + * XPLMGetDatad + * + * Read a double precision floating point dataref and return its value. The + * return value is the dataref value or 0.0 if the dataref is NULL or the + * plugin is disabled. + * + */ +XPLM_API double XPLMGetDatad( + XPLMDataRef inDataRef); + +/* + * XPLMSetDatad + * + * Write a new value to a double precision floating point data ref. This + * routine is a no-op if the plugin publishing the dataref is disabled, the + * dataref is NULL, or the dataref is not writable. + * + */ +XPLM_API void XPLMSetDatad( + XPLMDataRef inDataRef, + double inValue); + +/* + * XPLMGetDatavi + * + * Read a part of an integer array dataref. If you pass NULL for outValues, + * the routine will return the size of the array, ignoring inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatavi( + XPLMDataRef inDataRef, + int * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavi + * + * Write part or all of an integer array dataref. The values passed by + * inValues are written into the dataref starting at inOffset. Up to inCount + * values are written; however if the values would write "off the end" of the + * dataref array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatavi( + XPLMDataRef inDataRef, + int * inValues, + int inoffset, + int inCount); + +/* + * XPLMGetDatavf + * + * Read a part of a single precision floating point array dataref. If you pass + * NULL for outVaules, the routine will return the size of the array, ignoring + * inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatavf( + XPLMDataRef inDataRef, + float * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavf + * + * Write part or all of a single precision floating point array dataref. The + * values passed by inValues are written into the dataref starting at + * inOffset. Up to inCount values are written; however if the values would + * write "off the end" of the dataref array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatavf( + XPLMDataRef inDataRef, + float * inValues, + int inoffset, + int inCount); + +/* + * XPLMGetDatab + * + * Read a part of a byte array dataref. If you pass NULL for outVaules, the + * routine will return the size of the array, ignoring inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatab( + XPLMDataRef inDataRef, + void * outValue, /* Can be NULL */ + int inOffset, + int inMaxBytes); + +/* + * XPLMSetDatab + * + * Write part or all of a byte array dataref. The values passed by inValues + * are written into the dataref starting at inOffset. Up to inCount values are + * written; however if the values would write "off the end" of the dataref + * array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatab( + XPLMDataRef inDataRef, + void * inValue, + int inOffset, + int inLength); + +/*************************************************************************** + * PUBLISHING YOUR PLUGIN'S DATA + ***************************************************************************/ +/* + * These functions allow you to create data references that other plug-ins and + * X-Plane can access via the above data access APIs. Data references + * published by other plugins operate the same as ones published by X-Plane in + * all manners except that your data reference will not be available to other + * plugins if/when your plugin is disabled. + * + * You share data by registering data provider callback functions. When a + * plug-in requests your data, these callbacks are then called. You provide + * one callback to return the value when a plugin 'reads' it and another to + * change the value when a plugin 'writes' it. + * + * Important: you must pick a prefix for your datarefs other than "sim/" - + * this prefix is reserved for X-Plane. The X-Plane SDK website contains a + * registry where authors can select a unique first word for dataref names, to + * prevent dataref collisions between plugins. + * + */ + + +/* + * XPLMGetDatai_f + * + * Data provider function pointers. + * + * These define the function pointers you provide to get or set data. Note + * that you are passed a generic pointer for each one. This is the same + * pointer you pass in your register routine; you can use it to locate plugin + * variables, etc. + * + * The semantics of your callbacks are the same as the dataref accessor above + * - basically routines like XPLMGetDatai are just pass-throughs from a caller + * to your plugin. Be particularly mindful in implementing array dataref + * read-write accessors; you are responsible for avoiding overruns, supporting + * offset read/writes, and handling a read with a NULL buffer. + * + */ +typedef int (* XPLMGetDatai_f)( + void * inRefcon); + +/* + * XPLMSetDatai_f + * + */ +typedef void (* XPLMSetDatai_f)( + void * inRefcon, + int inValue); + +/* + * XPLMGetDataf_f + * + */ +typedef float (* XPLMGetDataf_f)( + void * inRefcon); + +/* + * XPLMSetDataf_f + * + */ +typedef void (* XPLMSetDataf_f)( + void * inRefcon, + float inValue); + +/* + * XPLMGetDatad_f + * + */ +typedef double (* XPLMGetDatad_f)( + void * inRefcon); + +/* + * XPLMSetDatad_f + * + */ +typedef void (* XPLMSetDatad_f)( + void * inRefcon, + double inValue); + +/* + * XPLMGetDatavi_f + * + */ +typedef int (* XPLMGetDatavi_f)( + void * inRefcon, + int * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavi_f + * + */ +typedef void (* XPLMSetDatavi_f)( + void * inRefcon, + int * inValues, + int inOffset, + int inCount); + +/* + * XPLMGetDatavf_f + * + */ +typedef int (* XPLMGetDatavf_f)( + void * inRefcon, + float * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavf_f + * + */ +typedef void (* XPLMSetDatavf_f)( + void * inRefcon, + float * inValues, + int inOffset, + int inCount); + +/* + * XPLMGetDatab_f + * + */ +typedef int (* XPLMGetDatab_f)( + void * inRefcon, + void * outValue, /* Can be NULL */ + int inOffset, + int inMaxLength); + +/* + * XPLMSetDatab_f + * + */ +typedef void (* XPLMSetDatab_f)( + void * inRefcon, + void * inValue, + int inOffset, + int inLength); + +/* + * XPLMRegisterDataAccessor + * + * This routine creates a new item of data that can be read and written. Pass + * in the data's full name for searching, the type(s) of the data for + * accessing, and whether the data can be written to. For each data type you + * support, pass in a read accessor function and a write accessor function if + * necessary. Pass NULL for data types you do not support or write accessors + * if you are read-only. + * + * You are returned a data ref for the new item of data created. You can use + * this data ref to unregister your data later or read or write from it. + * + */ +XPLM_API XPLMDataRef XPLMRegisterDataAccessor( + const char * inDataName, + XPLMDataTypeID inDataType, + int inIsWritable, + XPLMGetDatai_f inReadInt, + XPLMSetDatai_f inWriteInt, + XPLMGetDataf_f inReadFloat, + XPLMSetDataf_f inWriteFloat, + XPLMGetDatad_f inReadDouble, + XPLMSetDatad_f inWriteDouble, + XPLMGetDatavi_f inReadIntArray, + XPLMSetDatavi_f inWriteIntArray, + XPLMGetDatavf_f inReadFloatArray, + XPLMSetDatavf_f inWriteFloatArray, + XPLMGetDatab_f inReadData, + XPLMSetDatab_f inWriteData, + void * inReadRefcon, + void * inWriteRefcon); + +/* + * XPLMUnregisterDataAccessor + * + * Use this routine to unregister any data accessors you may have registered. + * You unregister a data ref by the XPLMDataRef you get back from + * registration. Once you unregister a data ref, your function pointer will + * not be called anymore. + * + */ +XPLM_API void XPLMUnregisterDataAccessor( + XPLMDataRef inDataRef); + +/*************************************************************************** + * SHARING DATA BETWEEN MULTIPLE PLUGINS + ***************************************************************************/ +/* + * The data reference registration APIs from the previous section allow a + * plugin to publish data in a one-owner manner; the plugin that publishes the + * data reference owns the real memory that the data ref uses. This is + * satisfactory for most cases, but there are also cases where plugnis need to + * share actual data. + * + * With a shared data reference, no one plugin owns the actual memory for the + * data reference; the plugin SDK allocates that for you. When the first + * plugin asks to 'share' the data, the memory is allocated. When the data is + * changed, every plugin that is sharing the data is notified. + * + * Shared data references differ from the 'owned' data references from the + * previous section in a few ways: + * + * * With shared data references, any plugin can create the data reference; + * with owned plugins one plugin must create the data reference and others + * subscribe. (This can be a problem if you don't know which set of plugins + * will be present). + * + * * With shared data references, every plugin that is sharing the data is + * notified when the data is changed. With owned data references, only the + * one owner is notified when the data is changed. + * + * * With shared data references, you cannot access the physical memory of the + * data reference; you must use the XPLMGet... and XPLMSet... APIs. With an + * owned data reference, the one owning data reference can manipulate the + * data reference's memory in any way it sees fit. + * + * Shared data references solve two problems: if you need to have a data + * reference used by several plugins but do not know which plugins will be + * installed, or if all plugins sharing data need to be notified when that + * data is changed, use shared data references. + * + */ + + +/* + * XPLMDataChanged_f + * + * An XPLMDataChanged_f is a callback that the XPLM calls whenever any other + * plug-in modifies shared data. A refcon you provide is passed back to help + * identify which data is being changed. In response, you may want to call one + * of the XPLMGetDataxxx routines to find the new value of the data. + * + */ +typedef void (* XPLMDataChanged_f)( + void * inRefcon); + +/* + * XPLMShareData + * + * This routine connects a plug-in to shared data, creating the shared data if + * necessary. inDataName is a standard path for the data ref, and inDataType + * specifies the type. This function will create the data if it does not + * exist. If the data already exists but the type does not match, an error is + * returned, so it is important that plug-in authors collaborate to establish + * public standards for shared data. + * + * If a notificationFunc is passed in and is not NULL, that notification + * function will be called whenever the data is modified. The notification + * refcon will be passed to it. This allows your plug-in to know which shared + * data was changed if multiple shared data are handled by one callback, or if + * the plug-in does not use global variables. + * + * A one is returned for successfully creating or finding the shared data; a + * zero if the data already exists but is of the wrong type. + * + */ +XPLM_API int XPLMShareData( + const char * inDataName, + XPLMDataTypeID inDataType, + XPLMDataChanged_f inNotificationFunc, + void * inNotificationRefcon); + +/* + * XPLMUnshareData + * + * This routine removes your notification function for shared data. Call it + * when done with the data to stop receiving change notifications. Arguments + * must match XPLMShareData. The actual memory will not necessarily be freed, + * since other plug-ins could be using it. + * + */ +XPLM_API int XPLMUnshareData( + const char * inDataName, + XPLMDataTypeID inDataType, + XPLMDataChanged_f inNotificationFunc, + void * inNotificationRefcon); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDefs.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDefs.h new file mode 100644 index 0000000..2e95b81 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDefs.h @@ -0,0 +1,514 @@ +#ifndef _XPLMDefs_h_ +#define _XPLMDefs_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDefs + ***************************************************************************/ +/* + * This file is contains the cross-platform and basic definitions for the + * X-Plane SDK. + * + * The preprocessor macros APL and IBM must be defined to specify the + * compilation target; define APL to 1 and IBM 0 to compile on Macintosh and + * APL to 0 and IBM to 1 for Windows. You must specify these macro definitions + * before including XPLMDefs.h or any other XPLM headers. You can do this + * using the -D command line option or a preprocessor header. + * + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#if IBM +#include +#else +#include +#endif +/*************************************************************************** + * DLL Definitions + ***************************************************************************/ +/* + * These definitions control the importing and exporting of functions within + * the DLL. + * + * You can prefix your five required callbacks with the PLUGIN_API macro to + * declare them as exported C functions. The XPLM_API macro identifies + * functions that are provided to you via the plugin SDK. (Link against + * XPLM.lib to use these functions.) + * + */ + + +#ifdef __cplusplus + #if APL + #if __GNUC__ >= 4 + #define PLUGIN_API extern "C" __attribute__((visibility("default"))) + #elif __MACH__ + #define PLUGIN_API extern "C" + #else + #define PLUGIN_API extern "C" __declspec(dllexport) + #endif + #elif IBM + #define PLUGIN_API extern "C" __declspec(dllexport) + #elif LIN + #if __GNUC__ >= 4 + #define PLUGIN_API extern "C" __attribute__((visibility("default"))) + #else + #define PLUGIN_API extern "C" + #endif + #else + #error "Platform not defined!" + #endif +#else + #if APL + #if __GNUC__ >= 4 + #define PLUGIN_API __attribute__((visibility("default"))) + #elif __MACH__ + #define PLUGIN_API + #else + #define PLUGIN_API __declspec(dllexport) + #endif + #elif IBM + #define PLUGIN_API __declspec(dllexport) + #elif LIN + #if __GNUC__ >= 4 + #define PLUGIN_API __attribute__((visibility("default"))) + #else + #define PLUGIN_API + #endif + #else + #error "Platform not defined!" + #endif +#endif + +#if APL + #if XPLM + #if __GNUC__ >= 4 + #define XPLM_API __attribute__((visibility("default"))) + #elif __MACH__ + #define XPLM_API + #else + #define XPLM_API __declspec(dllexport) + #endif + #else + #define XPLM_API + #endif +#elif IBM + #if XPLM + #define XPLM_API __declspec(dllexport) + #else + #define XPLM_API __declspec(dllimport) + #endif +#elif LIN + #if XPLM + #if __GNUC__ >= 4 + #define XPLM_API __attribute__((visibility("default"))) + #else + #define XPLM_API + #endif + #else + #define XPLM_API + #endif +#else + #error "Platform not defined!" +#endif + +/*************************************************************************** + * GLOBAL DEFINITIONS + ***************************************************************************/ +/* + * These definitions are used in all parts of the SDK. + * + */ + + +/* + * XPLMPluginID + * + * Each plug-in is identified by a unique integer ID. This ID can be used to + * disable or enable a plug-in, or discover what plug-in is 'running' at the + * time. A plug-in ID is unique within the currently running instance of + * X-Plane unless plug-ins are reloaded. Plug-ins may receive a different + * unique ID each time they are loaded. This includes the unloading and + * reloading of plugins that are part of the user's aircraft. + * + * For persistent identification of plug-ins, use XPLMFindPluginBySignature in + * XPLMUtiltiies.h + * + * -1 indicates no plug-in. + * + */ +typedef int XPLMPluginID; + +/* No plugin. */ +#define XPLM_NO_PLUGIN_ID (-1) + +/* X-Plane itself */ +#define XPLM_PLUGIN_XPLANE (0) + +/* The current XPLM revision is 4.00 (400). */ +#define kXPLM_Version (400) + +/* + * XPLMKeyFlags + * + * These bitfields define modifier keys in a platform independent way. When a + * key is pressed, a series of messages are sent to your plugin. The down + * flag is set in the first of these messages, and the up flag in the last. + * While the key is held down, messages are sent with neither to indicate that + * the key is being held down as a repeated character. + * + * The control flag is mapped to the control flag on Macintosh and PC. + * Generally X-Plane uses the control key and not the command key on + * Macintosh, providing a consistent interface across platforms that does not + * necessarily match the Macintosh user interface guidelines. There is not + * yet a way for plugins to access the Macintosh control keys without using + * #ifdefed code. + * + */ +enum { + /* The shift key is down */ + xplm_ShiftFlag = 1, + + /* The option or alt key is down */ + xplm_OptionAltFlag = 2, + + /* The control key is down* */ + xplm_ControlFlag = 4, + + /* The key is being pressed down */ + xplm_DownFlag = 8, + + /* The key is being released */ + xplm_UpFlag = 16, + + +}; +typedef int XPLMKeyFlags; + +/*************************************************************************** + * ASCII CONTROL KEY CODES + ***************************************************************************/ +/* + * These definitions define how various control keys are mapped to ASCII key + * codes. Not all key presses generate an ASCII value, so plugin code should + * be prepared to see null characters come from the keyboard...this usually + * represents a key stroke that has no equivalent ASCII, like a page-down + * press. Use virtual key codes to find these key strokes. + * + * ASCII key codes take into account modifier keys; shift keys will affect + * capitals and punctuation; control key combinations may have no vaild ASCII + * and produce NULL. To detect control-key combinations, use virtual key + * codes, not ASCII keys. + * + */ + + +#define XPLM_KEY_RETURN 13 + +#define XPLM_KEY_ESCAPE 27 + +#define XPLM_KEY_TAB 9 + +#define XPLM_KEY_DELETE 8 + +#define XPLM_KEY_LEFT 28 + +#define XPLM_KEY_RIGHT 29 + +#define XPLM_KEY_UP 30 + +#define XPLM_KEY_DOWN 31 + +#define XPLM_KEY_0 48 + +#define XPLM_KEY_1 49 + +#define XPLM_KEY_2 50 + +#define XPLM_KEY_3 51 + +#define XPLM_KEY_4 52 + +#define XPLM_KEY_5 53 + +#define XPLM_KEY_6 54 + +#define XPLM_KEY_7 55 + +#define XPLM_KEY_8 56 + +#define XPLM_KEY_9 57 + +#define XPLM_KEY_DECIMAL 46 + +/*************************************************************************** + * VIRTUAL KEY CODES + ***************************************************************************/ +/* + * These are cross-platform defines for every distinct keyboard press on the + * computer. Every physical key on the keyboard has a virtual key code. So + * the "two" key on the top row of the main keyboard has a different code from + * the "two" key on the numeric key pad. But the 'w' and 'W' character are + * indistinguishable by virtual key code because they are the same physical + * key (one with and one without the shift key). + * + * Use virtual key codes to detect keystrokes that do not have ASCII + * equivalents, allow the user to map the numeric keypad separately from the + * main keyboard, and detect control key and other modifier-key combinations + * that generate ASCII control key sequences (many of which are not available + * directly via character keys in the SDK). + * + * To assign virtual key codes we started with the Microsoft set but made some + * additions and changes. A few differences: + * + * 1. Modifier keys are not available as virtual key codes. You cannot get + * distinct modifier press and release messages. Please do not try to use + * modifier keys as regular keys; doing so will almost certainly interfere + * with users' abilities to use the native X-Plane key bindings. + * 2. Some keys that do not exist on both Mac and PC keyboards are removed. + * 3. Do not assume that the values of these keystrokes are interchangeable + * with MS v-keys. + * + */ + + +#define XPLM_VK_BACK 0x08 + +#define XPLM_VK_TAB 0x09 + +#define XPLM_VK_CLEAR 0x0C + +#define XPLM_VK_RETURN 0x0D + +#define XPLM_VK_ESCAPE 0x1B + +#define XPLM_VK_SPACE 0x20 + +#define XPLM_VK_PRIOR 0x21 + +#define XPLM_VK_NEXT 0x22 + +#define XPLM_VK_END 0x23 + +#define XPLM_VK_HOME 0x24 + +#define XPLM_VK_LEFT 0x25 + +#define XPLM_VK_UP 0x26 + +#define XPLM_VK_RIGHT 0x27 + +#define XPLM_VK_DOWN 0x28 + +#define XPLM_VK_SELECT 0x29 + +#define XPLM_VK_PRINT 0x2A + +#define XPLM_VK_EXECUTE 0x2B + +#define XPLM_VK_SNAPSHOT 0x2C + +#define XPLM_VK_INSERT 0x2D + +#define XPLM_VK_DELETE 0x2E + +#define XPLM_VK_HELP 0x2F + +/* XPLM_VK_0 thru XPLM_VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ +#define XPLM_VK_0 0x30 + +#define XPLM_VK_1 0x31 + +#define XPLM_VK_2 0x32 + +#define XPLM_VK_3 0x33 + +#define XPLM_VK_4 0x34 + +#define XPLM_VK_5 0x35 + +#define XPLM_VK_6 0x36 + +#define XPLM_VK_7 0x37 + +#define XPLM_VK_8 0x38 + +#define XPLM_VK_9 0x39 + +/* XPLM_VK_A thru XPLM_VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ +#define XPLM_VK_A 0x41 + +#define XPLM_VK_B 0x42 + +#define XPLM_VK_C 0x43 + +#define XPLM_VK_D 0x44 + +#define XPLM_VK_E 0x45 + +#define XPLM_VK_F 0x46 + +#define XPLM_VK_G 0x47 + +#define XPLM_VK_H 0x48 + +#define XPLM_VK_I 0x49 + +#define XPLM_VK_J 0x4A + +#define XPLM_VK_K 0x4B + +#define XPLM_VK_L 0x4C + +#define XPLM_VK_M 0x4D + +#define XPLM_VK_N 0x4E + +#define XPLM_VK_O 0x4F + +#define XPLM_VK_P 0x50 + +#define XPLM_VK_Q 0x51 + +#define XPLM_VK_R 0x52 + +#define XPLM_VK_S 0x53 + +#define XPLM_VK_T 0x54 + +#define XPLM_VK_U 0x55 + +#define XPLM_VK_V 0x56 + +#define XPLM_VK_W 0x57 + +#define XPLM_VK_X 0x58 + +#define XPLM_VK_Y 0x59 + +#define XPLM_VK_Z 0x5A + +#define XPLM_VK_NUMPAD0 0x60 + +#define XPLM_VK_NUMPAD1 0x61 + +#define XPLM_VK_NUMPAD2 0x62 + +#define XPLM_VK_NUMPAD3 0x63 + +#define XPLM_VK_NUMPAD4 0x64 + +#define XPLM_VK_NUMPAD5 0x65 + +#define XPLM_VK_NUMPAD6 0x66 + +#define XPLM_VK_NUMPAD7 0x67 + +#define XPLM_VK_NUMPAD8 0x68 + +#define XPLM_VK_NUMPAD9 0x69 + +#define XPLM_VK_MULTIPLY 0x6A + +#define XPLM_VK_ADD 0x6B + +#define XPLM_VK_SEPARATOR 0x6C + +#define XPLM_VK_SUBTRACT 0x6D + +#define XPLM_VK_DECIMAL 0x6E + +#define XPLM_VK_DIVIDE 0x6F + +#define XPLM_VK_F1 0x70 + +#define XPLM_VK_F2 0x71 + +#define XPLM_VK_F3 0x72 + +#define XPLM_VK_F4 0x73 + +#define XPLM_VK_F5 0x74 + +#define XPLM_VK_F6 0x75 + +#define XPLM_VK_F7 0x76 + +#define XPLM_VK_F8 0x77 + +#define XPLM_VK_F9 0x78 + +#define XPLM_VK_F10 0x79 + +#define XPLM_VK_F11 0x7A + +#define XPLM_VK_F12 0x7B + +#define XPLM_VK_F13 0x7C + +#define XPLM_VK_F14 0x7D + +#define XPLM_VK_F15 0x7E + +#define XPLM_VK_F16 0x7F + +#define XPLM_VK_F17 0x80 + +#define XPLM_VK_F18 0x81 + +#define XPLM_VK_F19 0x82 + +#define XPLM_VK_F20 0x83 + +#define XPLM_VK_F21 0x84 + +#define XPLM_VK_F22 0x85 + +#define XPLM_VK_F23 0x86 + +#define XPLM_VK_F24 0x87 + +/* The following definitions are extended and are not based on the Microsoft * + * key set. */ +#define XPLM_VK_EQUAL 0xB0 + +#define XPLM_VK_MINUS 0xB1 + +#define XPLM_VK_RBRACE 0xB2 + +#define XPLM_VK_LBRACE 0xB3 + +#define XPLM_VK_QUOTE 0xB4 + +#define XPLM_VK_SEMICOLON 0xB5 + +#define XPLM_VK_BACKSLASH 0xB6 + +#define XPLM_VK_COMMA 0xB7 + +#define XPLM_VK_SLASH 0xB8 + +#define XPLM_VK_PERIOD 0xB9 + +#define XPLM_VK_BACKQUOTE 0xBA + +#define XPLM_VK_ENTER 0xBB + +#define XPLM_VK_NUMPAD_ENT 0xBC + +#define XPLM_VK_NUMPAD_EQ 0xBD + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDisplay.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDisplay.h new file mode 100644 index 0000000..db5006d --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMDisplay.h @@ -0,0 +1,1658 @@ +#ifndef _XPLMDisplay_h_ +#define _XPLMDisplay_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDisplay + ***************************************************************************/ +/* + * This API provides the basic hooks to draw in X-Plane and create user + * interface. All X-Plane drawing is done in OpenGL. The X-Plane plug-in + * manager takes care of properly setting up the OpenGL context and matrices. + * You do not decide when in your code's execution to draw; X-Plane tells you + * (via callbacks) when it is ready to have your plugin draw. + * + * X-Plane's drawing strategy is straightforward: every "frame" the screen is + * rendered by drawing the 3-D scene (dome, ground, objects, airplanes, etc.) + * and then drawing the cockpit on top of it. Alpha blending is used to + * overlay the cockpit over the world (and the gauges over the panel, etc.). + * X-Plane user interface elements (including windows like the map, the main + * menu, etc.) are then drawn on top of the cockpit. + * + * There are two ways you can draw: directly and in a window. + * + * Direct drawing (deprecated!---more on that below) involves drawing to the + * screen before or after X-Plane finishes a phase of drawing. When you draw + * directly, you can specify whether X-Plane is to complete this phase or not. + * This allows you to do three things: draw before X-Plane does (under it), + * draw after X-Plane does (over it), or draw instead of X-Plane. + * + * To draw directly, you register a callback and specify which phase you want + * to intercept. The plug-in manager will call you over and over to draw that + * phase. + * + * Direct drawing allows you to override scenery, panels, or anything. Note + * that you cannot assume that you are the only plug-in drawing at this phase. + * + * Direct drawing is deprecated; at some point in the X-Plane 11 run, it will + * likely become unsupported entirely as X-Plane transitions from OpenGL to + * modern graphics API backends (e.g., Vulkan, Metal, etc.). In the long term, + * plugins should use the XPLMInstance API for drawing 3-D objects---this will + * be much more efficient than general 3-D OpenGL drawing, and it will + * actually be supported by the new graphics backends. We do not yet know what + * the post-transition API for generic 3-D drawing will look like (if it + * exists at all). + * + * In contrast to direct drawing, window drawing provides a higher level + * functionality. With window drawing, you create a 2-D window that takes up a + * portion of the screen. Window drawing is always two dimensional. Window + * drawing is front-to-back controlled; you can specify that you want your + * window to be brought on top, and other plug-ins may put their window on top + * of you. Window drawing also allows you to sign up for key presses and + * receive mouse clicks. + * + * Drawing into the screen of an avionics device, like a GPS or a Primary + * Flight Display, is a way to extend or replace X-Plane's avionics. Most + * screens can be displayed both in a 3d cockpit or + * 2d panel, and also in separate popup windows. By installing drawing + * callbacks for a certain avionics device, you can change or extend the + * appearance of that device regardless whether it's installed in a 3d + * cockpit or used in a separate display for home cockpits because you leave + * the window managing to X-Plane. + * + * There are three ways to get keystrokes: + * + * 1. If you create a window, the window can take keyboard focus. It will + * then receive all keystrokes. If no window has focus, X-Plane receives + * keystrokes. Use this to implement typing in dialog boxes, etc. Only + * one window may have focus at a time; your window will be notified if it + * loses focus. + * 2. If you need low level access to the keystroke stream, install a key + * sniffer. Key sniffers can be installed above everything or right in + * front of the sim. + * 3. If you would like to associate key strokes with commands/functions in + * your plug-in, you should simply register a command (via + * XPLMCreateCommand()) and allow users to bind whatever key they choose to + * that command. Another (now deprecated) method of doing so is to use a + * hot key---a key-specific callback. Hotkeys are sent based on virtual + * key strokes, so any key may be distinctly mapped with any modifiers. + * Hot keys can be remapped by other plug-ins. As a plug-in, you don't + * have to worry about what your hot key ends up mapped to; other plug-ins + * may provide a UI for remapping keystrokes. So hotkeys allow a user to + * resolve conflicts and customize keystrokes. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * DRAWING CALLBACKS + ***************************************************************************/ +/* + * Basic drawing callbacks, for low level intercepting of X-Plane's render + * loop. The purpose of drawing callbacks is to provide targeted additions or + * replacements to X-Plane's graphics environment (for example, to add extra + * custom objects, or replace drawing of the AI aircraft). Do not assume that + * the drawing callbacks will be called in the order implied by the + * enumerations. Also do not assume that each drawing phase ends before + * another begins; they may be nested. + * + * Note that all APIs in this section are deprecated, and will likely be + * removed during the X-Plane 11 run as part of the transition to + * Vulkan/Metal/etc. See the XPLMInstance API for future-proof drawing of 3-D + * objects. + * + */ + + +/* + * XPLMDrawingPhase + * + * This constant indicates which part of drawing we are in. Drawing is done + * from the back to the front. We get a callback before or after each item. + * Metaphases provide access to the beginning and end of the 3d (scene) and + * 2d (cockpit) drawing in a manner that is independent of new phases added + * via X-Plane implementation. + * + * **NOTE**: As of XPLM302 the legacy 3D drawing phases (xplm_Phase_FirstScene + * to xplm_Phase_LastScene) are deprecated. When running under X-Plane 11.50 + * with the modern Vulkan or Metal backend, X-Plane will no longer call + * these drawing phases. There is a new drawing phase, xplm_Phase_Modern3D, + * which is supported under OpenGL and Vulkan which is called out roughly + * where the old before xplm_Phase_Airplanes phase was for blending. This + * phase is *NOT* supported under Metal and comes with potentially + * substantial performance overhead. Please do *NOT* opt into this phase if + * you don't do any actual drawing that requires the depth buffer in some + * way! + * + * **WARNING**: As X-Plane's scenery evolves, some drawing phases may cease to + * exist and new ones may be invented. If you need a particularly specific + * use of these codes, consult Austin and/or be prepared to revise your code + * as X-Plane evolves. + * + */ +enum { +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. This is the earliest point at which you can draw * + * in 3-d. */ + xplm_Phase_FirstScene = 0, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing of land and water. */ + xplm_Phase_Terrain = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing runways and other airport detail. */ + xplm_Phase_Airports = 10, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing roads, trails, trains, etc. */ + xplm_Phase_Vectors = 15, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. 3-d objects (houses, smokestacks, etc. */ + xplm_Phase_Objects = 20, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. External views of airplanes, both yours and the * + * AI aircraft. */ + xplm_Phase_Airplanes = 25, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. This is the last point at which you can draw in * + * 3-d. */ + xplm_Phase_LastScene = 30, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM302) + /* A chance to do modern 3D drawing. */ + xplm_Phase_Modern3D = 31, + +#endif /* XPLM302 */ + /* This is the first phase where you can draw in 2-d. */ + xplm_Phase_FirstCockpit = 35, + + /* The non-moving parts of the aircraft panel. */ + xplm_Phase_Panel = 40, + + /* The moving parts of the aircraft panel. */ + xplm_Phase_Gauges = 45, + + /* Floating windows from plugins. */ + xplm_Phase_Window = 50, + + /* The last chance to draw in 2d. */ + xplm_Phase_LastCockpit = 55, + +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMap3D = 100, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMap2D = 101, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMapProfile = 102, + +#endif /* XPLM200 */ + +}; +typedef int XPLMDrawingPhase; + +/* + * XPLMDrawCallback_f + * + * This is the prototype for a low level drawing callback. You are passed in + * the phase and whether it is before or after. If you are before the phase, + * return 1 to let X-Plane draw or 0 to suppress X-Plane drawing. If you are + * after the phase the return value is ignored. + * + * Refcon is a unique value that you specify when registering the callback, + * allowing you to slip a pointer to your own data to the callback. + * + * Upon entry the OpenGL context will be correctly set up for you and OpenGL + * will be in 'local' coordinates for 3d drawing and panel coordinates for 2d + * drawing. The OpenGL state (texturing, etc.) will be unknown. + * + */ +typedef int (* XPLMDrawCallback_f)( + XPLMDrawingPhase inPhase, + int inIsBefore, + void * inRefcon); + +/* + * XPLMRegisterDrawCallback + * + * This routine registers a low level drawing callback. Pass in the phase you + * want to be called for and whether you want to be called before or after. + * This routine returns 1 if the registration was successful, or 0 if the + * phase does not exist in this version of X-Plane. You may register a + * callback multiple times for the same or different phases as long as the + * refcon is unique each time. + * + * Note that this function will likely be removed during the X-Plane 11 run as + * part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + * future-proof drawing of 3-D objects. + * + */ +XPLM_API int XPLMRegisterDrawCallback( + XPLMDrawCallback_f inCallback, + XPLMDrawingPhase inPhase, + int inWantsBefore, + void * inRefcon); + +/* + * XPLMUnregisterDrawCallback + * + * This routine unregisters a draw callback. You must unregister a callback + * for each time you register a callback if you have registered it multiple + * times with different refcons. The routine returns 1 if it can find the + * callback to unregister, 0 otherwise. + * + * Note that this function will likely be removed during the X-Plane 11 run as + * part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + * future-proof drawing of 3-D objects. + * + */ +XPLM_API int XPLMUnregisterDrawCallback( + XPLMDrawCallback_f inCallback, + XPLMDrawingPhase inPhase, + int inWantsBefore, + void * inRefcon); + +#if defined(XPLM400) +/*************************************************************************** + * AVIONICS API + ***************************************************************************/ +/* + * Drawing callbacks for before and after X-Plane draws the instrument screen + * can be registered for every cockpit device. If the user plane does not + * have the device installed, your callback will not be called! Use the + * return value to enable or disable X-Plane's drawing. By drawing into the + * framebuffer of the avionics device, your modifications will be visible + * regardless whether the device's screen is in a 3d cockpit or a popup + * window. + * + */ + + +/* + * XPLMDeviceID + * + * This constant indicates the device we want to override or enhance. We can + * get a callback before or after each item. + * + */ +enum { + /* GNS430, pilot side. */ + xplm_device_GNS430_1 = 0, + + /* GNS430, copilot side. */ + xplm_device_GNS430_2 = 1, + + /* GNS530, pilot side. */ + xplm_device_GNS530_1 = 2, + + /* GNS530, copilot side. */ + xplm_device_GNS530_2 = 3, + + /* generic airliner CDU, pilot side. */ + xplm_device_CDU739_1 = 4, + + /* generic airliner CDU, copilot side. */ + xplm_device_CDU739_2 = 5, + + /* G1000 Primary Flight Display, pilot side. */ + xplm_device_G1000_PFD_1 = 6, + + /* G1000 Multifunction Display. */ + xplm_device_G1000_MFD = 7, + + /* G1000 Primary Flight Display, copilot side. */ + xplm_device_G1000_PFD_2 = 8, + + /* Primus CDU, pilot side. */ + xplm_device_CDU815_1 = 9, + + /* Primus CDU, copilot side. */ + xplm_device_CDU815_2 = 10, + + /* Primus Primary Flight Display, pilot side. */ + xplm_device_Primus_PFD_1 = 11, + + /* Primus Primary Flight Display, copilot side. */ + xplm_device_Primus_PFD_2 = 12, + + /* Primus Multifunction Display, pilot side. */ + xplm_device_Primus_MFD_1 = 13, + + /* Primus Multifunction Display, copilot side. */ + xplm_device_Primus_MFD_2 = 14, + + /* Primus Multifunction Display, central. */ + xplm_device_Primus_MFD_3 = 15, + + /* Primus Radio Management Unit, pilot side. */ + xplm_device_Primus_RMU_1 = 16, + + /* Primus Radio Management Unit, copilot side. */ + xplm_device_Primus_RMU_2 = 17, + + +}; +typedef int XPLMDeviceID; + +/* + * XPLMAvionicsCallback_f + * + * This is the prototype for your drawing callback. You are passed in the + * device you are enhancing/replacing, and whether it is before or after + * X-Plane drawing. If you are before X-Plane, return 1 to let X-Plane draw or + * 0 to suppress X-Plane drawing. If you are after the phase the return value + * is ignored. + * + * Refcon is a unique value that you specify when registering the callback, + * allowing you to slip a pointer to your own data to the callback. + * + * Upon entry the OpenGL context will be correctly set up for you and OpenGL + * will be in panel coordinates for 2d drawing. The OpenGL state (texturing, + * etc.) will be unknown. + * + */ +typedef int (* XPLMAvionicsCallback_f)( + XPLMDeviceID inDeviceID, + int inIsBefore, + void * inRefcon); + +/* + * XPLMAvionicsID + * + * This is an opaque identifier for an avionics display that you enhance or + * replace. When you register your callbacks (via + * XPLMRegisterAvionicsCallbacksEx()), you will specify callbacks to handle + * drawing, and get back such a handle. + * + */ +typedef void * XPLMAvionicsID; + +/* + * XPLMCustomizeAvionics_t + * + * The XPLMCustomizeAvionics_t structure defines all of the parameters used to + * replace or enhance avionics for using XPLMRegisterAvionicsCallbacksEx(). + * The structure will be expanded in future SDK APIs to include more features. + * Always set the structSize member to the size of your struct in bytes! + * + */ +typedef struct { + /* Used to inform XPLMRegisterAvionicsCallbacksEx() of the SDK version you * + * compiled against; should always be set to sizeof(XPLMCustomizeAvionics_t) */ + int structSize; + /* Which avionics device you want your drawing applied to. */ + XPLMDeviceID deviceId; + /* The draw callback to be called before X-Plane draws. */ + XPLMAvionicsCallback_f drawCallbackBefore; + /* The draw callback to be called after X-Plane has drawn. */ + XPLMAvionicsCallback_f drawCallbackAfter; + /* A reference which will be passed into each of your draw callbacks. Use this* + * to pass information to yourself as needed. */ + void * refcon; +} XPLMCustomizeAvionics_t; + +/* + * XPLMRegisterAvionicsCallbacksEx + * + * This routine registers your callbacks for a device. This returns a handle. + * If the returned handle is NULL, there was a problem interpreting your + * input, most likely the struct size was wrong for your SDK version. If the + * returned handle is not NULL, your callbacks will be called according to + * schedule as long as your plugin is not deactivated, or unloaded, or your + * call XPLMUnregisterAvionicsCallbacks(). + * + */ +XPLM_API XPLMAvionicsID XPLMRegisterAvionicsCallbacksEx( + XPLMCustomizeAvionics_t * inParams); + +/* + * XPLMUnregisterAvionicsCallbacks + * + * This routine unregisters your callbacks for a device. They will no longer + * be called. + * + */ +XPLM_API void XPLMUnregisterAvionicsCallbacks( + XPLMAvionicsID inAvionicsId); + +#endif /* XPLM400 */ +/*************************************************************************** + * WINDOW API + ***************************************************************************/ +/* + * The window API provides a high-level abstraction for drawing with UI + * interaction. + * + * Windows may operate in one of two modes: legacy (for plugins compiled + * against old versions of the XPLM, as well as windows created via the + * deprecated XPLMCreateWindow() function, rather than XPLMCreateWindowEx()), + * or modern (for windows compiled against the XPLM300 or newer API, and + * created via XPLMCreateWindowEx()). + * + * Modern windows have access to new X-Plane 11 windowing features, like + * support for new positioning modes (including being "popped out" into their + * own first-class window in the operating system). They can also optionally + * be decorated in the style of X-Plane 11 windows (like the map). + * + * Modern windows operate in "boxel" units. A boxel ("box of pixels") is a + * unit of virtual pixels which, depending on X-Plane's scaling, may + * correspond to an arbitrary NxN "box" of real pixels on screen. Because + * X-Plane handles this scaling automatically, you can effectively treat the + * units as though you were simply drawing in pixels, and know that when + * X-Plane is running with 150% or 200% scaling, your drawing will be + * automatically scaled (and likewise all mouse coordinates, screen bounds, + * etc. will also be auto-scaled). + * + * In contrast, legacy windows draw in true screen pixels, and thus tend to + * look quite small when X-Plane is operating in a scaled mode. + * + * Legacy windows have their origin in the lower left of the main X-Plane + * window. In contrast, since modern windows are not constrained to the main + * window, they have their origin in the lower left of the entire global + * desktop space, and the lower left of the main X-Plane window is not + * guaranteed to be (0, 0). In both cases, x increases as you move left, and y + * increases as you move up. + * + */ + + +/* + * XPLMWindowID + * + * This is an opaque identifier for a window. You use it to control your + * window. When you create a window (via either XPLMCreateWindow() or + * XPLMCreateWindowEx()), you will specify callbacks to handle drawing, mouse + * interaction, etc. + * + */ +typedef void * XPLMWindowID; + +/* + * XPLMDrawWindow_f + * + * A callback to handle 2-D drawing of your window. You are passed in your + * window and its refcon. Draw the window. You can use other XPLM functions + * from this header to find the current dimensions of your window, etc. When + * this callback is called, the OpenGL context will be set properly for 2-D + * window drawing. + * + * **Note**: Because you are drawing your window over a background, you can + * make a translucent window easily by simply not filling in your entire + * window's bounds. + * + */ +typedef void (* XPLMDrawWindow_f)( + XPLMWindowID inWindowID, + void * inRefcon); + +/* + * XPLMHandleKey_f + * + * This function is called when a key is pressed or keyboard focus is taken + * away from your window. If losingFocus is 1, you are losing the keyboard + * focus, otherwise a key was pressed and inKey contains its character. + * + * The window ID passed in will be your window for key presses, or the other + * window taking focus when losing focus. Note that in the modern plugin + * system, often focus is taken by the window manager itself; for this resaon, + * the window ID may be zero when losing focus, and you should not write code + * that depends onit. + * + * The refcon passed in will be the one from registration, for both key + * presses and losing focus. + * + * Warning: this API declares virtual keys as a signed character; however the + * VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + * (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + * to an unsigned char to get correct comparisons in C. + * + */ +typedef void (* XPLMHandleKey_f)( + XPLMWindowID inWindowID, + char inKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefcon, + int losingFocus); + +/* + * XPLMMouseStatus + * + * When the mouse is clicked, your mouse click routine is called repeatedly. + * It is first called with the mouse down message. It is then called zero or + * more times with the mouse-drag message, and finally it is called once with + * the mouse up message. All of these messages will be directed to the same + * window; you are guaranteed to not receive a drag or mouse-up event without + * first receiving the corresponding mouse-down. + * + */ +enum { + xplm_MouseDown = 1, + + xplm_MouseDrag = 2, + + xplm_MouseUp = 3, + + +}; +typedef int XPLMMouseStatus; + +/* + * XPLMHandleMouseClick_f + * + * You receive this call for one of three events: + * + * - when the user clicks the mouse button down + * - (optionally) when the user drags the mouse after a down-click, but before + * the up-click + * - when the user releases the down-clicked mouse button. + * + * You receive the x and y of the click, your window, and a refcon. Return 1 + * to consume the click, or 0 to pass it through. + * + * WARNING: passing clicks through windows (as of this writing) causes mouse + * tracking problems in X-Plane; do not use this feature! + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef int (* XPLMHandleMouseClick_f)( + XPLMWindowID inWindowID, + int x, + int y, + XPLMMouseStatus inMouse, + void * inRefcon); + +#if defined(XPLM200) +/* + * XPLMCursorStatus + * + * XPLMCursorStatus describes how you would like X-Plane to manage the cursor. + * See XPLMHandleCursor_f for more info. + * + */ +enum { + /* X-Plane manages the cursor normally, plugin does not affect the cusrsor. */ + xplm_CursorDefault = 0, + + /* X-Plane hides the cursor. */ + xplm_CursorHidden = 1, + + /* X-Plane shows the cursor as the default arrow. */ + xplm_CursorArrow = 2, + + /* X-Plane shows the cursor but lets you select an OS cursor. */ + xplm_CursorCustom = 3, + + +}; +typedef int XPLMCursorStatus; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMHandleCursor_f + * + * The SDK calls your cursor status callback when the mouse is over your + * plugin window. Return a cursor status code to indicate how you would like + * X-Plane to manage the cursor. If you return xplm_CursorDefault, the SDK + * will try lower-Z-order plugin windows, then let the sim manage the cursor. + * + * Note: you should never show or hide the cursor yourself---these APIs are + * typically reference-counted and thus cannot safely and predictably be used + * by the SDK. Instead return one of xplm_CursorHidden to hide the cursor or + * xplm_CursorArrow/xplm_CursorCustom to show the cursor. + * + * If you want to implement a custom cursor by drawing a cursor in OpenGL, use + * xplm_CursorHidden to hide the OS cursor and draw the cursor using a 2-d + * drawing callback (after xplm_Phase_Window is probably a good choice, but + * see deprecation warnings on the drawing APIs!). If you want to use a + * custom OS-based cursor, use xplm_CursorCustom to ask X-Plane to show the + * cursor but not affect its image. You can then use an OS specific call like + * SetThemeCursor (Mac) or SetCursor/LoadCursor (Windows). + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef XPLMCursorStatus (* XPLMHandleCursor_f)( + XPLMWindowID inWindowID, + int x, + int y, + void * inRefcon); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMHandleMouseWheel_f + * + * The SDK calls your mouse wheel callback when one of the mouse wheels is + * scrolled within your window. Return 1 to consume the mouse wheel movement + * or 0 to pass them on to a lower window. (If your window appears opaque to + * the user, you should consume mouse wheel scrolling even if it does + * nothing.) The number of "clicks" indicates how far the wheel was turned + * since the last callback. The wheel is 0 for the vertical axis or 1 for the + * horizontal axis (for OS/mouse combinations that support this). + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef int (* XPLMHandleMouseWheel_f)( + XPLMWindowID inWindowID, + int x, + int y, + int wheel, + int clicks, + void * inRefcon); +#endif /* XPLM200 */ + +#if defined(XPLM300) +/* + * XPLMWindowLayer + * + * XPLMWindowLayer describes where in the ordering of windows X-Plane should + * place a particular window. Windows in higher layers cover windows in lower + * layers. So, a given window might be at the top of its particular layer, but + * it might still be obscured by a window in a higher layer. (This happens + * frequently when floating windows, like X-Plane's map, are covered by a + * modal alert.) + * + * Your window's layer can only be specified when you create the window (in + * the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). For this reason, + * layering only applies to windows created with new X-Plane 11 GUI features. + * (Windows created using the older XPLMCreateWindow(), or windows compiled + * against a pre-XPLM300 version of the SDK will simply be placed in the + * flight overlay window layer.) + * + */ +enum { + /* The lowest layer, used for HUD-like displays while flying. */ + xplm_WindowLayerFlightOverlay = 0, + + /* Windows that "float" over the sim, like the X-Plane 11 map does. If you are* + * not sure which layer to create your window in, choose floating. */ + xplm_WindowLayerFloatingWindows = 1, + + /* An interruptive modal that covers the sim with a transparent black overlay * + * to draw the user's focus to the alert */ + xplm_WindowLayerModal = 2, + + /* "Growl"-style notifications that are visible in a corner of the screen, * + * even over modals */ + xplm_WindowLayerGrowlNotifications = 3, + + +}; +typedef int XPLMWindowLayer; +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMWindowDecoration + * + * XPLMWindowDecoration describes how "modern" windows will be displayed. This + * impacts both how X-Plane draws your window as well as certain mouse + * handlers. + * + * Your window's decoration can only be specified when you create the window + * (in the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). + * + */ +enum { + /* X-Plane will draw no decoration for your window, and apply no automatic * + * click handlers. The window will not stop click from passing through its * + * bounds. This is suitable for "windows" which request, say, the full screen * + * bounds, then only draw in a small portion of the available area. */ + xplm_WindowDecorationNone = 0, + + /* The default decoration for "native" windows, like the map. Provides a solid* + * background, as well as click handlers for resizing and dragging the window.*/ + xplm_WindowDecorationRoundRectangle = 1, + + /* X-Plane will draw no decoration for your window, nor will it provide resize* + * handlers for your window edges, but it will stop clicks from passing * + * through your windows bounds. */ + xplm_WindowDecorationSelfDecorated = 2, + + /* Like self-decorated, but with resizing; X-Plane will draw no decoration for* + * your window, but it will stop clicks from passing through your windows * + * bounds, and provide automatic mouse handlers for resizing. */ + xplm_WindowDecorationSelfDecoratedResizable = 3, + + +}; +typedef int XPLMWindowDecoration; +#endif /* XPLM301 */ + +#if defined(XPLM200) +/* + * XPLMCreateWindow_t + * + * The XPMCreateWindow_t structure defines all of the parameters used to + * create a modern window using XPLMCreateWindowEx(). The structure will be + * expanded in future SDK APIs to include more features. Always set the + * structSize member to the size of your struct in bytes! + * + * All windows created by this function in the XPLM300 version of the API are + * created with the new X-Plane 11 GUI features. This means your plugin will + * get to "know" about the existence of X-Plane windows other than the main + * window. All drawing and mouse callbacks for your window will occur in + * "boxels," giving your windows automatic support for high-DPI scaling in + * X-Plane. In addition, your windows can opt-in to decoration with the + * X-Plane 11 window styling, and you can use the + * XPLMSetWindowPositioningMode() API to make your window "popped out" into a + * first-class operating system window. + * + * Note that this requires dealing with your window's bounds in "global + * desktop" positioning units, rather than the traditional panel coordinate + * system. In global desktop coordinates, the main X-Plane window may not have + * its origin at coordinate (0, 0), and your own window may have negative + * coordinates. Assuming you don't implicitly assume (0, 0) as your origin, + * the only API change you should need is to start using + * XPLMGetMouseLocationGlobal() rather than XPLMGetMouseLocation(), and + * XPLMGetScreenBoundsGlobal() instead of XPLMGetScreenSize(). + * + * If you ask to be decorated as a floating window, you'll get the blue window + * control bar and blue backing that you see in X-Plane 11's normal "floating" + * windows (like the map). + * + */ +typedef struct { + /* Used to inform XPLMCreateWindowEx() of the SDK version you compiled * + * against; should always be set to sizeof(XPLMCreateWindow_t) */ + int structSize; + /* Left bound, in global desktop boxels */ + int left; + /* Top bound, in global desktop boxels */ + int top; + /* Right bound, in global desktop boxels */ + int right; + /* Bottom bound, in global desktop boxels */ + int bottom; + int visible; + XPLMDrawWindow_f drawWindowFunc; + /* A callback to handle the user left-clicking within your window (or NULL to * + * ignore left clicks) */ + XPLMHandleMouseClick_f handleMouseClickFunc; + XPLMHandleKey_f handleKeyFunc; + XPLMHandleCursor_f handleCursorFunc; + XPLMHandleMouseWheel_f handleMouseWheelFunc; + /* A reference which will be passed into each of your window callbacks. Use * + * this to pass information to yourself as needed. */ + void * refcon; +#if defined(XPLM301) + /* Specifies the type of X-Plane 11-style "wrapper" you want around your * + * window, if any */ + XPLMWindowDecoration decorateAsFloatingWindow; +#endif /* XPLM301 */ +#if defined(XPLM300) + XPLMWindowLayer layer; +#endif /* XPLM300 */ +#if defined(XPLM300) + /* A callback to handle the user right-clicking within your window (or NULL to* + * ignore right clicks) */ + XPLMHandleMouseClick_f handleRightClickFunc; +#endif /* XPLM300 */ +} XPLMCreateWindow_t; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMCreateWindowEx + * + * This routine creates a new "modern" window. You pass in an + * XPLMCreateWindow_t structure with all of the fields set in. You must set + * the structSize of the structure to the size of the actual structure you + * used. Also, you must provide functions for every callback---you may not + * leave them null! (If you do not support the cursor or mouse wheel, use + * functions that return the default values.) + * + */ +XPLM_API XPLMWindowID XPLMCreateWindowEx( + XPLMCreateWindow_t * inParams); +#endif /* XPLM200 */ + +/* + * XPLMCreateWindow + * + * Deprecated as of XPLM300. + * + * This routine creates a new legacy window. Unlike modern windows (created + * via XPLMCreateWindowEx()), legacy windows do not have access to X-Plane 11 + * features like automatic scaling for high-DPI screens, native window styles, + * or support for being "popped out" into first-class operating system + * windows. + * + * Pass in the dimensions and offsets to the window's bottom left corner from + * the bottom left of the screen. You can specify whether the window is + * initially visible or not. Also, you pass in three callbacks to run the + * window and a refcon. This function returns a window ID you can use to + * refer to the new window. + * + * NOTE: Legacy windows do not have "frames"; you are responsible for drawing + * the background and frame of the window. Higher level libraries have + * routines which make this easy. + * + */ +XPLM_API XPLMWindowID XPLMCreateWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible, + XPLMDrawWindow_f inDrawCallback, + XPLMHandleKey_f inKeyCallback, + XPLMHandleMouseClick_f inMouseCallback, + void * inRefcon); + +/* + * XPLMDestroyWindow + * + * This routine destroys a window. The window's callbacks are not called + * after this call. Keyboard focus is removed from the window before + * destroying it. + * + */ +XPLM_API void XPLMDestroyWindow( + XPLMWindowID inWindowID); + +/* + * XPLMGetScreenSize + * + * This routine returns the size of the main X-Plane OpenGL window in pixels. + * This number can be used to get a rough idea of the amount of detail the + * user will be able to see when drawing in 3-d. + * + */ +XPLM_API void XPLMGetScreenSize( + int * outWidth, /* Can be NULL */ + int * outHeight); /* Can be NULL */ + +#if defined(XPLM300) +/* + * XPLMGetScreenBoundsGlobal + * + * This routine returns the bounds of the "global" X-Plane desktop, in boxels. + * Unlike the non-global version XPLMGetScreenSize(), this is multi-monitor + * aware. There are three primary consequences of multimonitor awareness. + * + * First, if the user is running X-Plane in full-screen on two or more + * monitors (typically configured using one full-screen window per monitor), + * the global desktop will be sized to include all X-Plane windows. + * + * Second, the origin of the screen coordinates is not guaranteed to be (0, + * 0). Suppose the user has two displays side-by-side, both running at 1080p. + * Suppose further that they've configured their OS to make the left display + * their "primary" monitor, and that X-Plane is running in full-screen on + * their right monitor only. In this case, the global desktop bounds would be + * the rectangle from (1920, 0) to (3840, 1080). If the user later asked + * X-Plane to draw on their primary monitor as well, the bounds would change + * to (0, 0) to (3840, 1080). + * + * Finally, if the usable area of the virtual desktop is not a perfect + * rectangle (for instance, because the monitors have different resolutions or + * because one monitor is configured in the operating system to be above and + * to the right of the other), the global desktop will include any wasted + * space. Thus, if you have two 1080p monitors, and monitor 2 is configured to + * have its bottom left touch monitor 1's upper right, your global desktop + * area would be the rectangle from (0, 0) to (3840, 2160). + * + * Note that popped-out windows (windows drawn in their own operating system + * windows, rather than "floating" within X-Plane) are not included in these + * bounds. + * + */ +XPLM_API void XPLMGetScreenBoundsGlobal( + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMReceiveMonitorBoundsGlobal_f + * + * This function is informed of the global bounds (in boxels) of a particular + * monitor within the X-Plane global desktop space. Note that X-Plane must be + * running in full screen on a monitor in order for that monitor to be passed + * to you in this callback. + * + */ +typedef void (* XPLMReceiveMonitorBoundsGlobal_f)( + int inMonitorIndex, + int inLeftBx, + int inTopBx, + int inRightBx, + int inBottomBx, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMGetAllMonitorBoundsGlobal + * + * This routine immediately calls you back with the bounds (in boxels) of each + * full-screen X-Plane window within the X-Plane global desktop space. Note + * that if a monitor is *not* covered by an X-Plane window, you cannot get its + * bounds this way. Likewise, monitors with only an X-Plane window (not in + * full-screen mode) will not be included. + * + * If X-Plane is running in full-screen and your monitors are of the same size + * and configured contiguously in the OS, then the combined global bounds of + * all full-screen monitors will match the total global desktop bounds, as + * returned by XPLMGetScreenBoundsGlobal(). (Of course, if X-Plane is running + * in windowed mode, this will not be the case. Likewise, if you have + * differently sized monitors, the global desktop space will include wasted + * space.) + * + * Note that this function's monitor indices match those provided by + * XPLMGetAllMonitorBoundsOS(), but the coordinates are different (since the + * X-Plane global desktop may not match the operating system's global desktop, + * and one X-Plane boxel may be larger than one pixel due to 150% or 200% + * scaling). + * + */ +XPLM_API void XPLMGetAllMonitorBoundsGlobal( + XPLMReceiveMonitorBoundsGlobal_f inMonitorBoundsCallback, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMReceiveMonitorBoundsOS_f + * + * This function is informed of the global bounds (in pixels) of a particular + * monitor within the operating system's global desktop space. Note that a + * monitor index being passed to you here does not indicate that X-Plane is + * running in full screen on this monitor, or even that any X-Plane windows + * exist on this monitor. + * + */ +typedef void (* XPLMReceiveMonitorBoundsOS_f)( + int inMonitorIndex, + int inLeftPx, + int inTopPx, + int inRightPx, + int inBottomPx, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMGetAllMonitorBoundsOS + * + * This routine immediately calls you back with the bounds (in pixels) of each + * monitor within the operating system's global desktop space. Note that + * unlike XPLMGetAllMonitorBoundsGlobal(), this may include monitors that have + * no X-Plane window on them. + * + * Note that this function's monitor indices match those provided by + * XPLMGetAllMonitorBoundsGlobal(), but the coordinates are different (since + * the X-Plane global desktop may not match the operating system's global + * desktop, and one X-Plane boxel may be larger than one pixel). + * + */ +XPLM_API void XPLMGetAllMonitorBoundsOS( + XPLMReceiveMonitorBoundsOS_f inMonitorBoundsCallback, + void * inRefcon); +#endif /* XPLM300 */ + +/* + * XPLMGetMouseLocation + * + * Deprecated in XPLM300. Modern windows should use + * XPLMGetMouseLocationGlobal() instead. + * + * This routine returns the current mouse location in pixels relative to the + * main X-Plane window. The bottom left corner of the main window is (0, 0). + * Pass NULL to not receive info about either parameter. + * + * Because this function gives the mouse position relative to the main X-Plane + * window (rather than in global bounds), this function should only be used by + * legacy windows. Modern windows should instead get the mouse position in + * global desktop coordinates using XPLMGetMouseLocationGlobal(). + * + * Note that unlike XPLMGetMouseLocationGlobal(), if the mouse goes outside + * the user's main monitor (for instance, to a pop out window or a secondary + * monitor), this function will not reflect it. + * + */ +XPLM_API void XPLMGetMouseLocation( + int * outX, /* Can be NULL */ + int * outY); /* Can be NULL */ + +#if defined(XPLM300) +/* + * XPLMGetMouseLocationGlobal + * + * Returns the current mouse location in global desktop boxels. Unlike + * XPLMGetMouseLocation(), the bottom left of the main X-Plane window is not + * guaranteed to be (0, 0)---instead, the origin is the lower left of the + * entire global desktop space. In addition, this routine gives the real mouse + * location when the mouse goes to X-Plane windows other than the primary + * display. Thus, it can be used with both pop-out windows and secondary + * monitors. + * + * This is the mouse location function to use with modern windows (i.e., those + * created by XPLMCreateWindowEx()). + * + * Pass NULL to not receive info about either parameter. + * + */ +XPLM_API void XPLMGetMouseLocationGlobal( + int * outX, /* Can be NULL */ + int * outY); /* Can be NULL */ +#endif /* XPLM300 */ + +/* + * XPLMGetWindowGeometry + * + * This routine returns the position and size of a window. The units and + * coordinate system vary depending on the type of window you have. + * + * If this is a legacy window (one compiled against a pre-XPLM300 version of + * the SDK, or an XPLM300 window that was not created using + * XPLMCreateWindowEx()), the units are pixels relative to the main X-Plane + * display. + * + * If, on the other hand, this is a new X-Plane 11-style window (compiled + * against the XPLM300 SDK and created using XPLMCreateWindowEx()), the units + * are global desktop boxels. + * + * Pass NULL to not receive any paramter. + * + */ +XPLM_API void XPLMGetWindowGeometry( + XPLMWindowID inWindowID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/* + * XPLMSetWindowGeometry + * + * This routine allows you to set the position and size of a window. + * + * The units and coordinate system match those of XPLMGetWindowGeometry(). + * That is, modern windows use global desktop boxel coordinates, while legacy + * windows use pixels relative to the main X-Plane display. + * + * Note that this only applies to "floating" windows (that is, windows that + * are drawn within the X-Plane simulation windows, rather than being "popped + * out" into their own first-class operating system windows). To set the + * position of windows whose positioning mode is xplm_WindowPopOut, you'll + * need to instead use XPLMSetWindowGeometryOS(). + * + */ +XPLM_API void XPLMSetWindowGeometry( + XPLMWindowID inWindowID, + int inLeft, + int inTop, + int inRight, + int inBottom); + +#if defined(XPLM300) +/* + * XPLMGetWindowGeometryOS + * + * This routine returns the position and size of a "popped out" window (i.e., + * a window whose positioning mode is xplm_WindowPopOut), in operating system + * pixels. Pass NULL to not receive any parameter. + * + */ +XPLM_API void XPLMGetWindowGeometryOS( + XPLMWindowID inWindowID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowGeometryOS + * + * This routine allows you to set the position and size, in operating system + * pixel coordinates, of a popped out window (that is, a window whose + * positioning mode is xplm_WindowPopOut, which exists outside the X-Plane + * simulation window, in its own first-class operating system window). + * + * Note that you are responsible for ensuring both that your window is popped + * out (using XPLMWindowIsPoppedOut()) and that a monitor really exists at the + * OS coordinates you provide (using XPLMGetAllMonitorBoundsOS()). + * + */ +XPLM_API void XPLMSetWindowGeometryOS( + XPLMWindowID inWindowID, + int inLeft, + int inTop, + int inRight, + int inBottom); +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMGetWindowGeometryVR + * + * Returns the width and height, in boxels, of a window in VR. Note that you + * are responsible for ensuring your window is in VR (using + * XPLMWindowIsInVR()). + * + */ +XPLM_API void XPLMGetWindowGeometryVR( + XPLMWindowID inWindowID, + int * outWidthBoxels, /* Can be NULL */ + int * outHeightBoxels); /* Can be NULL */ +#endif /* XPLM301 */ + +#if defined(XPLM301) +/* + * XPLMSetWindowGeometryVR + * + * This routine allows you to set the size, in boxels, of a window in VR (that + * is, a window whose positioning mode is xplm_WindowVR). + * + * Note that you are responsible for ensuring your window is in VR (using + * XPLMWindowIsInVR()). + * + */ +XPLM_API void XPLMSetWindowGeometryVR( + XPLMWindowID inWindowID, + int widthBoxels, + int heightBoxels); +#endif /* XPLM301 */ + +/* + * XPLMGetWindowIsVisible + * + * Returns true (1) if the specified window is visible. + * + */ +XPLM_API int XPLMGetWindowIsVisible( + XPLMWindowID inWindowID); + +/* + * XPLMSetWindowIsVisible + * + * This routine shows or hides a window. + * + */ +XPLM_API void XPLMSetWindowIsVisible( + XPLMWindowID inWindowID, + int inIsVisible); + +#if defined(XPLM300) +/* + * XPLMWindowIsPoppedOut + * + * True if this window has been popped out (making it a first-class window in + * the operating system), which in turn is true if and only if you have set + * the window's positioning mode to xplm_WindowPopOut. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK cannot be popped out.) + * + */ +XPLM_API int XPLMWindowIsPoppedOut( + XPLMWindowID inWindowID); +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMWindowIsInVR + * + * True if this window has been moved to the virtual reality (VR) headset, + * which in turn is true if and only if you have set the window's positioning + * mode to xplm_WindowVR. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM301 version of + * the SDK cannot be moved to VR.) + * + */ +XPLM_API int XPLMWindowIsInVR( + XPLMWindowID inWindowID); +#endif /* XPLM301 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowGravity + * + * A window's "gravity" controls how the window shifts as the whole X-Plane + * window resizes. A gravity of 1 means the window maintains its positioning + * relative to the right or top edges, 0 the left/bottom, and 0.5 keeps it + * centered. + * + * Default gravity is (0, 1, 0, 1), meaning your window will maintain its + * position relative to the top left and will not change size as its + * containing window grows. + * + * If you wanted, say, a window that sticks to the top of the screen (with a + * constant height), but which grows to take the full width of the window, you + * would pass (0, 1, 1, 1). Because your left and right edges would maintain + * their positioning relative to their respective edges of the screen, the + * whole width of your window would change with the X-Plane window. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will simply get the default gravity.) + * + */ +XPLM_API void XPLMSetWindowGravity( + XPLMWindowID inWindowID, + float inLeftGravity, + float inTopGravity, + float inRightGravity, + float inBottomGravity); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowResizingLimits + * + * Sets the minimum and maximum size of the client rectangle of the given + * window. (That is, it does not include any window styling that you might + * have asked X-Plane to apply on your behalf.) All resizing operations are + * constrained to these sizes. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will have no minimum or maximum size.) + * + */ +XPLM_API void XPLMSetWindowResizingLimits( + XPLMWindowID inWindowID, + int inMinWidthBoxels, + int inMinHeightBoxels, + int inMaxWidthBoxels, + int inMaxHeightBoxels); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMWindowPositioningMode + * + * XPLMWindowPositionMode describes how X-Plane will position your window on + * the user's screen. X-Plane will maintain this positioning mode even as the + * user resizes their window or adds/removes full-screen monitors. + * + * Positioning mode can only be set for "modern" windows (that is, windows + * created using XPLMCreateWindowEx() and compiled against the XPLM300 SDK). + * Windows created using the deprecated XPLMCreateWindow(), or windows + * compiled against a pre-XPLM300 version of the SDK will simply get the + * "free" positioning mode. + * + */ +enum { + /* The default positioning mode. Set the window geometry and its future * + * position will be determined by its window gravity, resizing limits, and * + * user interactions. */ + xplm_WindowPositionFree = 0, + + /* Keep the window centered on the monitor you specify */ + xplm_WindowCenterOnMonitor = 1, + + /* Keep the window full screen on the monitor you specify */ + xplm_WindowFullScreenOnMonitor = 2, + + /* Like gui_window_full_screen_on_monitor, but stretches over *all* monitors * + * and popout windows. This is an obscure one... unless you have a very good * + * reason to need it, you probably don't! */ + xplm_WindowFullScreenOnAllMonitors = 3, + + /* A first-class window in the operating system, completely separate from the * + * X-Plane window(s) */ + xplm_WindowPopOut = 4, + +#if defined(XPLM301) + /* A floating window visible on the VR headset */ + xplm_WindowVR = 5, + +#endif /* XPLM301 */ + +}; +typedef int XPLMWindowPositioningMode; +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowPositioningMode + * + * Sets the policy for how X-Plane will position your window. + * + * Some positioning modes apply to a particular monitor. For those modes, you + * can pass a negative monitor index to position the window on the main + * X-Plane monitor (the screen with the X-Plane menu bar at the top). Or, if + * you have a specific monitor you want to position your window on, you can + * pass a real monitor index as received from, e.g., + * XPLMGetAllMonitorBoundsOS(). + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will always use xplm_WindowPositionFree.) + * + */ +XPLM_API void XPLMSetWindowPositioningMode( + XPLMWindowID inWindowID, + XPLMWindowPositioningMode inPositioningMode, + int inMonitorIndex); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowTitle + * + * Sets the name for a window. This only applies to windows that opted-in to + * styling as an X-Plane 11 floating window (i.e., with styling mode + * xplm_WindowDecorationRoundRectangle) when they were created using + * XPLMCreateWindowEx(). + * + */ +XPLM_API void XPLMSetWindowTitle( + XPLMWindowID inWindowID, + const char * inWindowTitle); +#endif /* XPLM300 */ + +/* + * XPLMGetWindowRefCon + * + * Returns a window's reference constant, the unique value you can use for + * your own purposes. + * + */ +XPLM_API void * XPLMGetWindowRefCon( + XPLMWindowID inWindowID); + +/* + * XPLMSetWindowRefCon + * + * Sets a window's reference constant. Use this to pass data to yourself in + * the callbacks. + * + */ +XPLM_API void XPLMSetWindowRefCon( + XPLMWindowID inWindowID, + void * inRefcon); + +/* + * XPLMTakeKeyboardFocus + * + * This routine gives a specific window keyboard focus. Keystrokes will be + * sent to that window. Pass a window ID of 0 to remove keyboard focus from + * any plugin-created windows and instead pass keyboard strokes directly to + * X-Plane. + * + */ +XPLM_API void XPLMTakeKeyboardFocus( + XPLMWindowID inWindow); + +/* + * XPLMHasKeyboardFocus + * + * Returns true (1) if the indicated window has keyboard focus. Pass a window + * ID of 0 to see if no plugin window has focus, and all keystrokes will go + * directly to X-Plane. + * + */ +XPLM_API int XPLMHasKeyboardFocus( + XPLMWindowID inWindow); + +/* + * XPLMBringWindowToFront + * + * This routine brings the window to the front of the Z-order for its layer. + * Windows are brought to the front automatically when they are created. + * Beyond that, you should make sure you are front before handling mouse + * clicks. + * + * Note that this only brings your window to the front of its layer + * (XPLMWindowLayer). Thus, if you have a window in the floating window layer + * (xplm_WindowLayerFloatingWindows), but there is a modal window (in layer + * xplm_WindowLayerModal) above you, you would still not be the true frontmost + * window after calling this. (After all, the window layers are strictly + * ordered, and no window in a lower layer can ever be above any window in a + * higher one.) + * + */ +XPLM_API void XPLMBringWindowToFront( + XPLMWindowID inWindow); + +/* + * XPLMIsWindowInFront + * + * This routine returns true if the window you passed in is the frontmost + * visible window in its layer (XPLMWindowLayer). + * + * Thus, if you have a window at the front of the floating window layer + * (xplm_WindowLayerFloatingWindows), this will return true even if there is a + * modal window (in layer xplm_WindowLayerModal) above you. (Not to worry, + * though: in such a case, X-Plane will not pass clicks or keyboard input down + * to your layer until the window above stops "eating" the input.) + * + * Note that legacy windows are always placed in layer + * xplm_WindowLayerFlightOverlay, while modern-style windows default to + * xplm_WindowLayerFloatingWindows. This means it's perfectly consistent to + * have two different plugin-created windows (one legacy, one modern) *both* + * be in the front (of their different layers!) at the same time. + * + */ +XPLM_API int XPLMIsWindowInFront( + XPLMWindowID inWindow); + +/*************************************************************************** + * KEY SNIFFERS + ***************************************************************************/ +/* + * Low-level keyboard handlers. Allows for intercepting keystrokes outside the + * normal rules of the user interface. + * + */ + + +/* + * XPLMKeySniffer_f + * + * This is the prototype for a low level key-sniffing function. Window-based + * UI _should not use this_! The windowing system provides high-level + * mediated keyboard access, via the callbacks you attach to your + * XPLMCreateWindow_t. By comparison, the key sniffer provides low level + * keyboard access. + * + * Key sniffers are provided to allow libraries to provide non-windowed user + * interaction. For example, the MUI library uses a key sniffer to do pop-up + * text entry. + * + * Return 1 to pass the key on to the next sniffer, the window manager, + * X-Plane, or whomever is down stream. Return 0 to consume the key. + * + * Warning: this API declares virtual keys as a signed character; however the + * VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + * (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + * to an unsigned char to get correct comparisons in C. + * + */ +typedef int (* XPLMKeySniffer_f)( + char inChar, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefcon); + +/* + * XPLMRegisterKeySniffer + * + * This routine registers a key sniffing callback. You specify whether you + * want to sniff before the window system, or only sniff keys the window + * system does not consume. You should ALMOST ALWAYS sniff non-control keys + * after the window system. When the window system consumes a key, it is + * because the user has "focused" a window. Consuming the key or taking + * action based on the key will produce very weird results. Returns + * 1 if successful. + * + */ +XPLM_API int XPLMRegisterKeySniffer( + XPLMKeySniffer_f inCallback, + int inBeforeWindows, + void * inRefcon); + +/* + * XPLMUnregisterKeySniffer + * + * This routine unregisters a key sniffer. You must unregister a key sniffer + * for every time you register one with the exact same signature. Returns 1 + * if successful. + * + */ +XPLM_API int XPLMUnregisterKeySniffer( + XPLMKeySniffer_f inCallback, + int inBeforeWindows, + void * inRefcon); + +/*************************************************************************** + * HOT KEYS + ***************************************************************************/ +/* + * Keystrokes that can be managed by others. These are lower-level than window + * keyboard handlers (i.e., callbacks you attach to your XPLMCreateWindow_t), + * but higher level than key sniffers. + * + */ + + +/* + * XPLMHotKey_f + * + * Your hot key callback simply takes a pointer of your choosing. + * + */ +typedef void (* XPLMHotKey_f)( + void * inRefcon); + +/* + * XPLMHotKeyID + * + * An opaque ID used to identify a hot key. + * + */ +typedef void * XPLMHotKeyID; + +/* + * XPLMRegisterHotKey + * + * This routine registers a hot key. You specify your preferred key stroke + * virtual key/flag combination, a description of what your callback does (so + * other plug-ins can describe the plug-in to the user for remapping) and a + * callback function and opaque pointer to pass in). A new hot key ID is + * returned. During execution, the actual key associated with your hot key + * may change, but you are insulated from this. + * + */ +XPLM_API XPLMHotKeyID XPLMRegisterHotKey( + char inVirtualKey, + XPLMKeyFlags inFlags, + const char * inDescription, + XPLMHotKey_f inCallback, + void * inRefcon); + +/* + * XPLMUnregisterHotKey + * + * Unregisters a hot key. You can only unregister your own hot keys. + * + */ +XPLM_API void XPLMUnregisterHotKey( + XPLMHotKeyID inHotKey); + +/* + * XPLMCountHotKeys + * + * Returns the number of current hot keys. + * + */ +XPLM_API int XPLMCountHotKeys(void); + +/* + * XPLMGetNthHotKey + * + * Returns a hot key by index, for iteration on all hot keys. + * + */ +XPLM_API XPLMHotKeyID XPLMGetNthHotKey( + int inIndex); + +/* + * XPLMGetHotKeyInfo + * + * Returns information about the hot key. Return NULL for any parameter you + * don't want info about. The description should be at least 512 chars long. + * + */ +XPLM_API void XPLMGetHotKeyInfo( + XPLMHotKeyID inHotKey, + char * outVirtualKey, /* Can be NULL */ + XPLMKeyFlags * outFlags, /* Can be NULL */ + char * outDescription, /* Can be NULL */ + XPLMPluginID * outPlugin); /* Can be NULL */ + +/* + * XPLMSetHotKeyCombination + * + * Remaps a hot key's keystrokes. You may remap another plugin's keystrokes. + * + */ +XPLM_API void XPLMSetHotKeyCombination( + XPLMHotKeyID inHotKey, + char inVirtualKey, + XPLMKeyFlags inFlags); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMGraphics.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMGraphics.h new file mode 100644 index 0000000..d7aef52 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMGraphics.h @@ -0,0 +1,437 @@ +#ifndef _XPLMGraphics_h_ +#define _XPLMGraphics_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMGraphics + ***************************************************************************/ +/* + * A few notes on coordinate systems: + * + * X-Plane uses three kinds of coordinates. Global coordinates are specified + * as latitude, longitude and elevation. This coordinate system never changes + * but is not very precise. + * + * OpenGL (or 'local') coordinates are cartesian and shift with the plane. + * They offer more precision and are used for 3-d OpenGL drawing. The X axis + * is aligned east-west with positive X meaning east. The Y axis is aligned + * straight up and down at the point 0,0,0 (but since the earth is round it is + * not truly straight up and down at other points). The Z axis is aligned + * north-south at 0, 0, 0 with positive Z pointing south (but since the earth + * is round it isn't exactly north-south as you move east or west of 0, 0, 0). + * One unit is one meter and the point 0,0,0 is on the surface of the earth at + * sea level for some latitude and longitude picked by the sim such that the + * user's aircraft is reasonably nearby. + * + * 2-d Panel coordinates are 2d, with the X axis horizontal and the Y axis + * vertical. The point 0,0 is the bottom left and 1024,768 is the upper + * right of the screen. This is true no matter what resolution the user's + * monitor is in; when running in higher resolution, graphics will be + * scaled. + * + * Use X-Plane's routines to convert between global and local coordinates. Do + * not attempt to do this conversion yourself; the precise 'roundness' of + * X-Plane's physics model may not match your own, and (to make things + * weirder) the user can potentially customize the physics of the current + * planet. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * X-PLANE GRAPHICS + ***************************************************************************/ +/* + * These routines allow you to use OpenGL with X-Plane. + * + */ + + +/* + * XPLMTextureID + * + * XPLM Texture IDs name well-known textures in the sim for you to use. This + * allows you to recycle textures from X-Plane, saving VRAM. + * + * *Warning*: do not use these enums. The only remaining use they have is to + * access the legacy compatibility v10 UI texture; if you need this, get it + * via the Widgets library. + * + */ +enum { + /* The bitmap that contains window outlines, button outlines, fonts, etc. */ + xplm_Tex_GeneralInterface = 0, + +#if defined(XPLM_DEPRECATED) + /* The exterior paint for the user's aircraft (daytime). */ + xplm_Tex_AircraftPaint = 1, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* The exterior light map for the user's aircraft. */ + xplm_Tex_AircraftLiteMap = 2, + +#endif /* XPLM_DEPRECATED */ + +}; +typedef int XPLMTextureID; + +/* + * XPLMSetGraphicsState + * + * XPLMSetGraphicsState changes OpenGL's fixed function pipeline state. You + * are not responsible for restoring any state that is accessed via + * XPLMSetGraphicsState, but you are responsible for not accessing this state + * directly. + * + * - inEnableFog - enables or disables fog, equivalent to: glEnable(GL_FOG); + * - inNumberTexUnits - enables or disables a number of multitexturing units. + * If the number is 0, 2d texturing is disabled entirely, as in + * glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a + * number of multitexturing units are enabled sequentially, starting with + * unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB); glEnable + * (GL_TEXTURE_2D); + * - inEnableLighting - enables or disables OpenGL lighting, e.g. + * glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + * - inEnableAlphaTesting - enables or disables the alpha test per pixel, e.g. + * glEnable(GL_ALPHA_TEST); + * - inEnableAlphaBlending - enables or disables alpha blending per pixel, + * e.g. glEnable(GL_BLEND); + * - inEnableDepthTesting - enables per pixel depth testing, as in + * glEnable(GL_DEPTH_TEST); + * - inEnableDepthWriting - enables writing back of depth information to the + * depth bufffer, as in glDepthMask(GL_TRUE); + * + * The purpose of this function is to change OpenGL state while keeping + * X-Plane aware of the state changes; this keeps X-Plane from getting + * surprised by OGL state changes, and prevents X-Plane and plug-ins from + * having to set all state before all draws; XPLMSetGraphicsState internally + * skips calls to change state that is already properly enabled. + * + * X-Plane does not have a 'default' OGL state for plug-ins with respect to + * the above state vector; plug-ins should totally set OGL state using this + * API before drawing. Use XPLMSetGraphicsState instead of any of the above + * OpenGL calls. + * + * WARNING: Any routine that performs drawing (e.g. XPLMDrawString or widget + * code) may change X-Plane's state. Always set state before drawing after + * unknown code has executed. + * + * *Deprecation Warnings*: X-Plane's lighting and fog environemnt is + * significantly more complex than the fixed function pipeline can express; + * do not assume that lighting and fog state is a good approximation for 3-d + * drawing. Prefer to use XPLMInstancing to draw objects. All calls to + * XPLMSetGraphicsState should have no fog or lighting. + * + */ +XPLM_API void XPLMSetGraphicsState( + int inEnableFog, + int inNumberTexUnits, + int inEnableLighting, + int inEnableAlphaTesting, + int inEnableAlphaBlending, + int inEnableDepthTesting, + int inEnableDepthWriting); + +/* + * XPLMBindTexture2d + * + * XPLMBindTexture2d changes what texture is bound to the 2d texturing + * target. This routine caches the current 2d texture across all texturing + * units in the sim and plug-ins, preventing extraneous binding. For + * example, consider several plug-ins running in series; if they all use the + * 'general interface' bitmap to do UI, calling this function will skip the + * rebinding of the general interface texture on all but the first plug-in, + * which can provide better frame rate son some graphics cards. + * + * inTextureID is the ID of the texture object to bind; inTextureUnit is a + * zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 + * units. (This number may increase in future versions of X-Plane.) + * + * Use this routine instead of glBindTexture(GL_TEXTURE_2D, ....); + * + */ +XPLM_API void XPLMBindTexture2d( + int inTextureNum, + int inTextureUnit); + +/* + * XPLMGenerateTextureNumbers + * + * Use this routine instead of glGenTextures to generate new texture object + * IDs. This routine historically ensured that plugins don't use texure IDs + * that X-Plane is reserving for its own use. + * + */ +XPLM_API void XPLMGenerateTextureNumbers( + int * outTextureIDs, + int inCount); + +#if defined(XPLM_DEPRECATED) +/* + * XPLMGetTexture + * + * XPLMGetTexture returns the OpenGL texture ID of an X-Plane texture based on + * a generic identifying code. For example, you can get the texture for + * X-Plane's UI bitmaps. + * + */ +XPLM_API int XPLMGetTexture( + XPLMTextureID inTexture); +#endif /* XPLM_DEPRECATED */ + +/* + * XPLMWorldToLocal + * + * This routine translates coordinates from latitude, longitude, and altitude + * to local scene coordinates. Latitude and longitude are in decimal degrees, + * and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + * meters in the local OpenGL coordinate system. + * + */ +XPLM_API void XPLMWorldToLocal( + double inLatitude, + double inLongitude, + double inAltitude, + double * outX, + double * outY, + double * outZ); + +/* + * XPLMLocalToWorld + * + * This routine translates a local coordinate triplet back into latitude, + * longitude, and altitude. Latitude and longitude are in decimal degrees, + * and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + * meters in the local OpenGL coordinate system. + * + * NOTE: world coordinates are less precise than local coordinates; you should + * try to avoid round tripping from local to world and back. + * + */ +XPLM_API void XPLMLocalToWorld( + double inX, + double inY, + double inZ, + double * outLatitude, + double * outLongitude, + double * outAltitude); + +/* + * XPLMDrawTranslucentDarkBox + * + * This routine draws a translucent dark box, partially obscuring parts of the + * screen but making text easy to read. This is the same graphics primitive + * used by X-Plane to show text files and ATC info. + * + */ +XPLM_API void XPLMDrawTranslucentDarkBox( + int inLeft, + int inTop, + int inRight, + int inBottom); + +/*************************************************************************** + * X-PLANE TEXT + ***************************************************************************/ + +/* + * XPLMFontID + * + * X-Plane features some fixed-character fonts. Each font may have its own + * metrics. + * + * WARNING: Some of these fonts are no longer supported or may have changed + * geometries. For maximum copmatibility, see the comments below. + * + * Note: X-Plane 7 supports proportional-spaced fonts. Since no measuring + * routine is available yet, the SDK will normally draw using a fixed-width + * font. You can use a dataref to enable proportional font drawing on XP7 if + * you want to. + * + */ +enum { + /* Mono-spaced font for user interface. Available in all versions of the SDK.*/ + xplmFont_Basic = 0, + +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Menus = 1, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Metal = 2, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Led = 3, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_LedWide = 4, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelHUD = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelEFIS = 6, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelGPS = 7, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosGA = 8, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosBC = 9, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosHM = 10, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosGANarrow = 11, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosBCNarrow = 12, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosHMNarrow = 13, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Timer = 14, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_FullRound = 15, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_SmallRound = 16, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Menus_Localized = 17, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM200) + /* Proportional UI font. */ + xplmFont_Proportional = 18, + +#endif /* XPLM200 */ + +}; +typedef int XPLMFontID; + +/* + * XPLMDrawString + * + * This routine draws a NULL termianted string in a given font. Pass in the + * lower left pixel that the character is to be drawn onto. Also pass the + * character and font ID. This function returns the x offset plus the width of + * all drawn characters. The color to draw in is specified as a pointer to an + * array of three floating point colors, representing RGB intensities from 0.0 + * to 1.0. + * + */ +XPLM_API void XPLMDrawString( + float * inColorRGB, + int inXOffset, + int inYOffset, + char * inChar, + int * inWordWrapWidth, /* Can be NULL */ + XPLMFontID inFontID); + +/* + * XPLMDrawNumber + * + * This routine draws a number similar to the digit editing fields in + * PlaneMaker and data output display in X-Plane. Pass in a color, a + * position, a floating point value, and formatting info. Specify how many + * integer and how many decimal digits to show and whether to show a sign, as + * well as a character set. This routine returns the xOffset plus width of the + * string drawn. + * + */ +XPLM_API void XPLMDrawNumber( + float * inColorRGB, + int inXOffset, + int inYOffset, + double inValue, + int inDigits, + int inDecimals, + int inShowSign, + XPLMFontID inFontID); + +/* + * XPLMGetFontDimensions + * + * This routine returns the width and height of a character in a given font. + * It also tells you if the font only supports numeric digits. Pass NULL if + * you don't need a given field. Note that for a proportional font the width + * will be an arbitrary, hopefully average width. + * + */ +XPLM_API void XPLMGetFontDimensions( + XPLMFontID inFontID, + int * outCharWidth, /* Can be NULL */ + int * outCharHeight, /* Can be NULL */ + int * outDigitsOnly); /* Can be NULL */ + +#if defined(XPLM200) +/* + * XPLMMeasureString + * + * This routine returns the width in pixels of a string using a given font. + * The string is passed as a pointer plus length (and does not need to be null + * terminated); this is used to allow for measuring substrings. The return + * value is floating point; it is possible that future font drawing may allow + * for fractional pixels. + * + */ +XPLM_API float XPLMMeasureString( + XPLMFontID inFontID, + const char * inChar, + int inNumChars); +#endif /* XPLM200 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMInstance.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMInstance.h new file mode 100644 index 0000000..d2a8f2c --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMInstance.h @@ -0,0 +1,136 @@ +#ifndef _XPLMInstance_h_ +#define _XPLMInstance_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMInstance + ***************************************************************************/ +/* + * This API provides instanced drawing of X-Plane objects (.obj files). In + * contrast to old drawing APIs, which required you to draw your own objects + * per-frame, the instancing API allows you to simply register an OBJ for + * drawing, then move or manipulate it later (as needed). + * + * This provides one tremendous benefit: it keeps all dataref operations for + * your object in one place. Because datarefs are main thread only, allowing + * dataref access anywhere is a serious performance bottleneck for the + * simulator---the whole simulator has to pause and wait for each dataref + * access. This performance penalty will only grow worse as X-Plane moves + * toward an ever more heavily multithreaded engine. + * + * The instancing API allows X-Plane to isolate all dataref manipulations for + * all plugin object drawing to one place, potentially providing huge + * performance gains. + * + * Here's how it works: + * + * When an instance is created, it provides a list of all datarefs you want to + * manipulate in for the OBJ in the future. This list of datarefs replaces the + * ad-hoc collections of dataref objects previously used by art assets. Then, + * per-frame, you can manipulate the instance by passing in a "block" of + * packed floats representing the current values of the datarefs for your + * instance. (Note that the ordering of this set of packed floats must exactly + * match the ordering of the datarefs when you created your instance.) + * + */ + +#include "XPLMDefs.h" +#include "XPLMScenery.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * Instance Creation and Destruction + ***************************************************************************/ +/* + * Registers and unregisters instances. + * + */ + + +/* + * XPLMInstanceRef + * + * An opaque handle to an instance. + * + */ +typedef void * XPLMInstanceRef; + +/* + * XPLMCreateInstance + * + * XPLMCreateInstance creates a new instance, managed by your plug-in, and + * returns a handle to the instance. A few important requirements: + * + * * The object passed in must be fully loaded and returned from the XPLM + * before you can create your instance; you cannot pass a null obj ref, nor + * can you change the ref later. + * + * * If you use any custom datarefs in your object, they must be registered + * before the object is loaded. This is true even if their data will be + * provided via the instance dataref list. + * + * * The instance dataref array must be a valid ptr to an array of at least + * one item that is null terminated. That is, if you do not want any + * datarefs, you must passa ptr to an array with a null item. You cannot + * pass null for this. + * + */ +XPLM_API XPLMInstanceRef XPLMCreateInstance( + XPLMObjectRef obj, + const char ** datarefs); + +/* + * XPLMDestroyInstance + * + * XPLMDestroyInstance destroys and deallocates your instance; once called, + * you are still responsible for releasing the OBJ ref. + * + * Tip: you can release your OBJ ref after you call XPLMCreateInstance as long + * as you never use it again; the instance will maintain its own reference to + * the OBJ and the object OBJ be deallocated when the instance is destroyed. + * + */ +XPLM_API void XPLMDestroyInstance( + XPLMInstanceRef instance); + +/*************************************************************************** + * Instance Manipulation + ***************************************************************************/ + +/* + * XPLMInstanceSetPosition + * + * Updates both the position of the instance and all datarefs you registered + * for it. Call this from a flight loop callback or UI callback. + * + * __DO NOT__ call XPLMInstanceSetPosition from a drawing callback; the whole + * point of instancing is that you do not need any drawing callbacks. Setting + * instance data from a drawing callback may have undefined consequences, and + * the drawing callback hurts FPS unnecessarily. + * + * The memory pointed to by the data pointer must be large enough to hold one + * float for every data ref you have registered, and must contain valid + * floating point data. + * + * BUG: before X-Plane 11.50, if you have no dataref registered, you must + * still pass a valid pointer for data and not null. + * + */ +XPLM_API void XPLMInstanceSetPosition( + XPLMInstanceRef instance, + const XPLMDrawInfo_t * new_position, + const float * data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMMap.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMMap.h new file mode 100644 index 0000000..8297471 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMMap.h @@ -0,0 +1,628 @@ +#ifndef _XPLMMap_h_ +#define _XPLMMap_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMMap + ***************************************************************************/ +/* + * This API allows you to create new layers within X-Plane maps. Your layers + * can draw arbitrary OpenGL, but they conveniently also have access to + * X-Plane's built-in icon and label drawing functions. + * + * As of X-Plane 11, map drawing happens in three stages: + * + * 1. backgrounds and "fill," + * 2. icons, and + * 3. labels. + * + * Thus, all background drawing gets layered beneath all icons, which likewise + * get layered beneath all labels. Within each stage, the map obeys a + * consistent layer ordering, such that "fill" layers (layers that cover a + * large amount of map area, like the terrain and clouds) appear beneath + * "markings" layers (like airport icons). This ensures that layers with fine + * details don't get obscured by layers with larger details. + * + * The XPLM map API reflects both aspects of this draw layering: you can + * register a layer as providing either markings or fill, and X-Plane will + * draw your fill layers beneath your markings layers (regardless of + * registration order). Likewise, you are guaranteed that your layer's icons + * (added from within an icon callback) will go above your layer's OpenGL + * drawing, and your labels will go above your icons. + * + * The XPLM guarantees that all plugin-created fill layers go on top of all + * native X-Plane fill layers, and all plugin-created markings layers go on + * top of all X-Plane markings layers (with the exception of the aircraft + * icons). It also guarantees that the draw order of your own plugin's layers + * will be consistent. But, for layers created by different plugins, the only + * guarantee is that we will draw all of one plugin's layers of each type + * (fill, then markings), then all of the others'; we don't guarantee which + * plugin's fill and markings layers go on top of the other's. + * + * As of X-Plane 11, maps use true cartographic projections for their drawing, + * and different maps may use different projections. For that reason, all + * drawing calls include an opaque handle for the projection you should use to + * do the drawing. Any time you would draw at a particular latitude/longitude, + * you'll need to ask the projection to translate that position into "map + * coordinates." (Note that the projection is guaranteed not to change between + * calls to your prepare-cache hook, so if you cache your map coordinates + * ahead of time, there's no need to re-project them when you actually draw.) + * + * In addition to mapping normal latitude/longitude locations into map + * coordinates, the projection APIs also let you know the current heading for + * north. (Since X-Plane 11 maps can rotate to match the heading of the user's + * aircraft, it's not safe to assume that north is at zero degrees rotation.) + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XPLM300) +/*************************************************************************** + * DRAWING CALLBACKS + ***************************************************************************/ +/* + * When you create a new map layer (using XPLMCreateMapLayer), you can provide + * any or all of these callbacks. They allow you to insert your own OpenGL + * drawing, text labels, and icons into the X-Plane map at the appropriate + * places, allowing your layer to behave as similarly to X-Plane's built-in + * layers as possible. + * + */ + + +/* + * XPLMMapLayerID + * + * This is an opaque handle for a plugin-created map layer. Pass it to the map + * drawing APIs from an appropriate callback to draw in the layer you created. + * + */ +typedef void * XPLMMapLayerID; + +/* + * XPLMMapProjectionID + * + * This is an opaque handle for a map projection. Pass it to the projection + * APIs to translate between map coordinates and latitude/longitudes. + * + */ +typedef void * XPLMMapProjectionID; + +/* + * XPLMMapStyle + * + * Indicates the visual style being drawn by the map. In X-Plane, the user can + * choose between a number of map types, and different map types may have use + * a different visual representation for the same elements (for instance, the + * visual style of the terrain layer changes drastically between the VFR and + * IFR layers), or certain layers may be disabled entirely in some map types + * (e.g., localizers are only visible in the IFR low-enroute style). + * + */ +enum { + xplm_MapStyle_VFR_Sectional = 0, + + xplm_MapStyle_IFR_LowEnroute = 1, + + xplm_MapStyle_IFR_HighEnroute = 2, + + +}; +typedef int XPLMMapStyle; + +/* + * XPLMMapDrawingCallback_f + * + * This is the OpenGL map drawing callback for plugin-created map layers. You + * can perform arbitrary OpenGL drawing from this callback, with one + * exception: changes to the Z-buffer are not permitted, and will result in + * map drawing errors. + * + * All drawing done from within this callback appears beneath all built-in + * X-Plane icons and labels, but above the built-in "fill" layers (layers + * providing major details, like terrain and water). Note, however, that the + * relative ordering between the drawing callbacks of different plugins is not + * guaranteed. + * + */ +typedef void (* XPLMMapDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapIconDrawingCallback_f + * + * This is the icon drawing callback that enables plugin-created map layers to + * draw icons using X-Plane's built-in icon drawing functionality. You can + * request an arbitrary number of PNG icons to be drawn via + * XPLMDrawMapIconFromSheet() from within this callback, but you may not + * perform any OpenGL drawing here. + * + * Icons enqueued by this function will appear above all OpenGL drawing + * (performed by your optional XPLMMapDrawingCallback_f), and above all + * built-in X-Plane map icons of the same layer type ("fill" or "markings," as + * determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + * however, that the relative ordering between the drawing callbacks of + * different plugins is not guaranteed. + * + */ +typedef void (* XPLMMapIconDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapLabelDrawingCallback_f + * + * This is the label drawing callback that enables plugin-created map layers + * to draw text labels using X-Plane's built-in labeling functionality. You + * can request an arbitrary number of text labels to be drawn via + * XPLMDrawMapLabel() from within this callback, but you may not perform any + * OpenGL drawing here. + * + * Labels enqueued by this function will appear above all OpenGL drawing + * (performed by your optional XPLMMapDrawingCallback_f), and above all + * built-in map icons and labels of the same layer type ("fill" or "markings," + * as determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + * however, that the relative ordering between the drawing callbacks of + * different plugins is not guaranteed. + * + */ +typedef void (* XPLMMapLabelDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * LAYER MANAGEMENT CALLBACKS + ***************************************************************************/ +/* + * These are various "bookkeeping" callbacks that your map layer can receive + * (if you provide the callback in your XPLMCreateMapLayer_t). They allow you + * to manage the lifecycle of your layer, as well as cache any + * computationally-intensive preparation you might need for drawing. + * + */ + + +/* + * XPLMMapPrepareCacheCallback_f + * + * A callback used to allow you to cache whatever information your layer needs + * to draw in the current map area. + * + * This is called each time the map's total bounds change. This is typically + * triggered by new DSFs being loaded, such that X-Plane discards old, + * now-distant DSFs and pulls in new ones. At that point, the available bounds + * of the map also change to match the new DSF area. + * + * By caching just the information you need to draw in this area, your future + * draw calls can be made faster, since you'll be able to simply "splat" your + * precomputed information each frame. + * + * We guarantee that the map projection will not change between successive + * prepare cache calls, nor will any draw call give you bounds outside these + * total map bounds. So, if you cache the projected map coordinates of all the + * items you might want to draw in the total map area, you can be guaranteed + * that no draw call will be asked to do any new work. + * + */ +typedef void (* XPLMMapPrepareCacheCallback_f)( + XPLMMapLayerID inLayer, + const float * inTotalMapBoundsLeftTopRightBottom, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapWillBeDeletedCallback_f + * + * Called just before your map layer gets deleted. Because SDK-created map + * layers have the same lifetime as the X-Plane map that contains them, if the + * map gets unloaded from memory, your layer will too. + * + */ +typedef void (* XPLMMapWillBeDeletedCallback_f)( + XPLMMapLayerID inLayer, + void * inRefcon); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP LAYER CREATION AND DESTRUCTION + ***************************************************************************/ +/* + * Enables the creation of new map layers. Layers are created for a particular + * instance of the X-Plane map. For instance, if you want your layer to appear + * in both the normal map interface and the Instructor Operator Station (IOS), + * you would need two separate calls to XPLMCreateMapLayer(), with two + * different values for your XPLMCreateMapLayer_t::layer_name. + * + * Your layer's lifetime will be determined by the lifetime of the map it is + * created in. If the map is destroyed (on the X-Plane side), your layer will + * be too, and you'll receive a callback to your + * XPLMMapWillBeDeletedCallback_f. + * + */ + + +/* + * XPLMMapLayerType + * + * Indicates the type of map layer you are creating. Fill layers will always + * be drawn beneath markings layers. + * + */ +enum { + /* A layer that draws "fill" graphics, like weather patterns, terrain, etc. * + * Fill layers frequently cover a large portion of the visible map area. */ + xplm_MapLayer_Fill = 0, + + /* A layer that provides markings for particular map features, like NAVAIDs, * + * airports, etc. Even dense markings layers cover a small portion of the * + * total map area. */ + xplm_MapLayer_Markings = 1, + + +}; +typedef int XPLMMapLayerType; + +/* Globally unique identifier for X-Plane's Map window, used as the * + * mapToCreateLayerIn parameter in XPLMCreateMapLayer_t */ +#define XPLM_MAP_USER_INTERFACE "XPLM_MAP_USER_INTERFACE" + +/* Globally unique identifier for X-Plane's Instructor Operator Station * + * window, used as the mapToCreateLayerIn parameter in XPLMCreateMapLayer_t */ +#define XPLM_MAP_IOS "XPLM_MAP_IOS" + +/* + * XPLMCreateMapLayer_t + * + * This structure defines all of the parameters used to create a map layer + * using XPLMCreateMapLayer. The structure will be expanded in future SDK APIs + * to include more features. Always set the structSize member to the size of + * your struct in bytes! + * + * Each layer must be associated with exactly one map instance in X-Plane. + * That map, and that map alone, will call your callbacks. Likewise, when that + * map is deleted, your layer will be as well. + * + */ +typedef struct { + /* Used to inform XPLMCreateMapLayer() of the SDK version you compiled * + * against; should always be set to sizeof(XPLMCreateMapLayer_t) */ + int structSize; + /* Globally unique string identifying the map you want this layer to appear * + * in. As of XPLM300, this is limited to one of XPLM_MAP_USER_INTERFACE or * + * XPLM_MAP_IOS */ + const char * mapToCreateLayerIn; + /* The type of layer you are creating, used to determine draw order (all * + * plugin-created markings layers are drawn above all plugin-created fill * + * layers) */ + XPLMMapLayerType layerType; + /* Optional callback to inform you this layer is being deleted (due to its * + * owning map being destroyed) */ + XPLMMapWillBeDeletedCallback_f willBeDeletedCallback; + /* Optional callback you want to use to prepare your draw cache when the map * + * bounds change (set to NULL if you don't want this callback) */ + XPLMMapPrepareCacheCallback_f prepCacheCallback; + /* Optional callback you want to use for arbitrary OpenGL drawing, which goes * + * beneath all icons in the map's layering system (set to NULL if you don't * + * want this callback) */ + XPLMMapDrawingCallback_f drawCallback; + /* Optional callback you want to use for drawing icons, which go above all * + * built-in X-Plane icons (except the aircraft) in the map's layering system * + * (set to NULL if you don't want this callback) */ + XPLMMapIconDrawingCallback_f iconCallback; + /* Optional callback you want to use for drawing map labels, which go above * + * all built-in X-Plane icons and labels (except those of aircraft) in the * + * map's layering system (set to NULL if you don't want this callback) */ + XPLMMapLabelDrawingCallback_f labelCallback; + /* True if you want a checkbox to be created in the map UI to toggle this * + * layer on and off; false if the layer should simply always be enabled */ + int showUiToggle; + /* Short label to use for this layer in the user interface */ + const char * layerName; + /* A reference to arbitrary data that will be passed to your callbacks */ + void * refcon; +} XPLMCreateMapLayer_t; + +/* + * XPLMCreateMapLayer + * + * This routine creates a new map layer. You pass in an XPLMCreateMapLayer_t + * structure with all of the fields set in. You must set the structSize of + * the structure to the size of the actual structure you used. + * + * Returns NULL if the layer creation failed. This happens most frequently + * because the map you specified in your + * XPLMCreateMapLayer_t::mapToCreateLayerIn field doesn't exist (that is, if + * XPLMMapExists() returns 0 for the specified map). You can use + * XPLMRegisterMapCreationHook() to get a notification each time a new map is + * opened in X-Plane, at which time you can create layers in it. + * + */ +XPLM_API XPLMMapLayerID XPLMCreateMapLayer( + XPLMCreateMapLayer_t * inParams); + +/* + * XPLMDestroyMapLayer + * + * Destroys a map layer you created (calling your + * XPLMMapWillBeDeletedCallback_f if applicable). Returns true if a deletion + * took place. + * + */ +XPLM_API int XPLMDestroyMapLayer( + XPLMMapLayerID inLayer); + +/* + * XPLMMapCreatedCallback_f + * + * A callback to notify your plugin that a new map has been created in + * X-Plane. This is the best time to add a custom map layer using + * XPLMCreateMapLayer(). + * + * No OpenGL drawing is permitted within this callback. + * + */ +typedef void (* XPLMMapCreatedCallback_f)( + const char * mapIdentifier, + void * refcon); + +/* + * XPLMRegisterMapCreationHook + * + * Registers your callback to receive a notification each time a new map is + * constructed in X-Plane. This callback is the best time to add your custom + * map layer using XPLMCreateMapLayer(). + * + * Note that you will not be notified about any maps that already exist---you + * can use XPLMMapExists() to check for maps that were created previously. + * + */ +XPLM_API void XPLMRegisterMapCreationHook( + XPLMMapCreatedCallback_f callback, + void * refcon); + +/* + * XPLMMapExists + * + * Returns 1 if the map with the specified identifier already exists in + * X-Plane. In that case, you can safely call XPLMCreateMapLayer() specifying + * that your layer should be added to that map. + * + */ +XPLM_API int XPLMMapExists( + const char * mapIdentifier); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP DRAWING + ***************************************************************************/ +/* + * These APIs are only valid from within a map drawing callback (one of + * XPLMIconDrawingCallback_t or XPLMMapLabelDrawingCallback_f). Your drawing + * callbacks are registered when you create a new map layer as part of your + * XPLMCreateMapLayer_t. The functions here hook into X-Plane's built-in map + * drawing functionality for icons and labels, so that you get a consistent + * style with the rest of the X-Plane map. + * + * Note that the X-Plane 11 map introduces a strict ordering: layers of type + * xplm_MapLayer_Fill get drawn beneath all xplm_MapLayer_Markings layers. + * Likewise, all OpenGL drawing (performed in your layer's + * XPLMMapDrawingCallback_f) will appear beneath any icons and labels you + * draw. + * + */ + + +/* + * XPLMMapOrientation + * + * Indicates whether a map element should be match its rotation to the map + * itself, or to the user interface. For instance, the map itself may be + * rotated such that "up" matches the user's aircraft, but you may want to + * draw a text label such that it is always rotated zero degrees relative to + * the user's perspective. In that case, you would have it draw with UI + * orientation. + * + */ +enum { + /* Orient such that a 0 degree rotation matches the map's north */ + xplm_MapOrientation_Map = 0, + + /* Orient such that a 0 degree rotation is "up" relative to the user interface*/ + xplm_MapOrientation_UI = 1, + + +}; +typedef int XPLMMapOrientation; + +/* + * XPLMDrawMapIconFromSheet + * + * Enables plugin-created map layers to draw PNG icons using X-Plane's + * built-in icon drawing functionality. Only valid from within an + * XPLMIconDrawingCallback_t (but you can request an arbitrary number of icons + * to be drawn from within your callback). + * + * X-Plane will automatically manage the memory for your texture so that it + * only has to be loaded from disk once as long as you continue drawing it + * per-frame. (When you stop drawing it, the memory may purged in a "garbage + * collection" pass, require a load from disk in the future.) + * + * Instead of having X-Plane draw a full PNG, this method allows you to use UV + * coordinates to request a portion of the image to be drawn. This allows you + * to use a single texture load (of an icon sheet, for example) to draw many + * icons. Doing so is much more efficient than drawing a dozen different small + * PNGs. + * + * The UV coordinates used here treat the texture you load as being comprised + * of a number of identically sized "cells." You specify the width and height + * in cells (ds and dt, respectively), as well as the coordinates within the + * cell grid for the sub-image you'd like to draw. + * + * Note that you can use different ds and dt values in subsequent calls with + * the same texture sheet. This enables you to use icons of different sizes in + * the same sheet if you arrange them properly in the PNG. + * + * This function is only valid from within an XPLMIconDrawingCallback_t (but + * you can request an arbitrary number of icons to be drawn from within your + * callback). + * + */ +XPLM_API void XPLMDrawMapIconFromSheet( + XPLMMapLayerID layer, + const char * inPngPath, + int s, + int t, + int ds, + int dt, + float mapX, + float mapY, + XPLMMapOrientation orientation, + float rotationDegrees, + float mapWidth); + +/* + * XPLMDrawMapLabel + * + * Enables plugin-created map layers to draw text labels using X-Plane's + * built-in labeling functionality. Only valid from within an + * XPLMMapLabelDrawingCallback_f (but you can request an arbitrary number of + * text labels to be drawn from within your callback). + * + */ +XPLM_API void XPLMDrawMapLabel( + XPLMMapLayerID layer, + const char * inText, + float mapX, + float mapY, + XPLMMapOrientation orientation, + float rotationDegrees); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP PROJECTIONS + ***************************************************************************/ +/* + * As of X-Plane 11, the map draws using true cartographic projections, and + * different maps may use different projections. Thus, to draw at a particular + * latitude and longitude, you must first transform your real-world + * coordinates into map coordinates. + * + * The map projection is also responsible for giving you the current scale of + * the map. That is, the projection can tell you how many map units correspond + * to 1 meter at a given point. + * + * Finally, the map projection can give you the current rotation of the map. + * Since X-Plane 11 maps can rotate to match the heading of the aircraft, the + * map's rotation can potentially change every frame. + * + */ + + +/* + * XPLMMapProject + * + * Projects a latitude/longitude into map coordinates. This is the inverse of + * XPLMMapUnproject(). + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API void XPLMMapProject( + XPLMMapProjectionID projection, + double latitude, + double longitude, + float * outX, + float * outY); + +/* + * XPLMMapUnproject + * + * Transforms map coordinates back into a latitude and longitude. This is the + * inverse of XPLMMapProject(). + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API void XPLMMapUnproject( + XPLMMapProjectionID projection, + float mapX, + float mapY, + double * outLatitude, + double * outLongitude); + +/* + * XPLMMapScaleMeter + * + * Returns the number of map units that correspond to a distance of one meter + * at a given set of map coordinates. + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API float XPLMMapScaleMeter( + XPLMMapProjectionID projection, + float mapX, + float mapY); + +/* + * XPLMMapGetNorthHeading + * + * Returns the heading (in degrees clockwise) from the positive Y axis in the + * cartesian mapping coordinate system to true north at the point passed in. + * You can use it as a clockwise rotational offset to align icons and other + * 2-d drawing with true north on the map, compensating for rotations in the + * map due to projection. + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API float XPLMMapGetNorthHeading( + XPLMMapProjectionID projection, + float mapX, + float mapY); + +#endif /* XPLM300 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMMenus.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMMenus.h new file mode 100644 index 0000000..f5802ab --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMMenus.h @@ -0,0 +1,290 @@ +#ifndef _XPLMMenus_h_ +#define _XPLMMenus_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMMenus + ***************************************************************************/ +/* + * Plug-ins can create menus in the menu bar of X-Plane. This is done by + * creating a menu and then creating items. Menus are referred to by an + * opaque ID. Items are referred to by (zero-based) index number. + * + * Menus are "sandboxed" between plugins---no plugin can access the menus of + * any other plugin. Furthermore, all menu indices are relative to your + * plugin's menus only; if your plugin creates two sub-menus in the Plugins + * menu at different times, it doesn't matter how many other plugins also + * create sub-menus of Plugins in the intervening time: your sub-menus will be + * given menu indices 0 and 1. (The SDK does some work in the back-end to + * filter out menus that are irrelevant to your plugin in order to deliver + * this consistency for each plugin.) + * + * When you create a menu item, you specify how we should handle clicks on + * that menu item. You can either have the XPLM trigger a callback (the + * XPLMMenuHandler_f associated with the menu that contains the item), or you + * can simply have a command be triggered (with no associated call to your + * menu handler). The advantage of the latter method is that X-Plane will + * display any keyboard shortcuts associated with the command. (In contrast, + * there are no keyboard shortcuts associated with menu handler callbacks with + * specific parameters.) + * + * Menu text in X-Plane is UTF8; X-Plane's character set covers latin, greek + * and cyrillic characters, Katakana, as well as some Japanese symbols. Some + * APIs have a inDeprecatedAndIgnored parameter that used to select a + * character set; since X-Plane 9 all localization is done via UTF-8 only. + * + */ + +#include "XPLMDefs.h" +#include "XPLMUtilities.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * XPLM MENUS + ***************************************************************************/ + +/* + * XPLMMenuCheck + * + * These enumerations define the various 'check' states for an X-Plane menu. + * 'checking' in X-Plane actually appears as a light which may or may not be + * lit. So there are three possible states. + * + */ +enum { + /* there is no symbol to the left of the menu item. */ + xplm_Menu_NoCheck = 0, + + /* the menu has a mark next to it that is unmarked (not lit). */ + xplm_Menu_Unchecked = 1, + + /* the menu has a mark next to it that is checked (lit). */ + xplm_Menu_Checked = 2, + + +}; +typedef int XPLMMenuCheck; + +/* + * XPLMMenuID + * + * This is a unique ID for each menu you create. + * + */ +typedef void * XPLMMenuID; + +/* + * XPLMMenuHandler_f + * + * A menu handler function takes two reference pointers, one for the menu + * (specified when the menu was created) and one for the item (specified when + * the item was created). + * + */ +typedef void (* XPLMMenuHandler_f)( + void * inMenuRef, + void * inItemRef); + +/* + * XPLMFindPluginsMenu + * + * This function returns the ID of the plug-ins menu, which is created for you + * at startup. + * + */ +XPLM_API XPLMMenuID XPLMFindPluginsMenu(void); + +#if defined(XPLM300) +/* + * XPLMFindAircraftMenu + * + * This function returns the ID of the menu for the currently-loaded aircraft, + * used for showing aircraft-specific commands. + * + * The aircraft menu is created by X-Plane at startup, but it remains hidden + * until it is populated via XPLMAppendMenuItem() or + * XPLMAppendMenuItemWithCommand(). + * + * Only plugins loaded with the user's current aircraft are allowed to access + * the aircraft menu. For all other plugins, this will return NULL, and any + * attempts to add menu items to it will fail. + * + */ +XPLM_API XPLMMenuID XPLMFindAircraftMenu(void); +#endif /* XPLM300 */ + +/* + * XPLMCreateMenu + * + * This function creates a new menu and returns its ID. It returns NULL if + * the menu cannot be created. Pass in a parent menu ID and an item index to + * create a submenu, or NULL for the parent menu to put the menu in the menu + * bar. The menu's name is only used if the menu is in the menubar. You also + * pass a handler function and a menu reference value. Pass NULL for the + * handler if you do not need callbacks from the menu (for example, if it only + * contains submenus). + * + * Important: you must pass a valid, non-empty menu title even if the menu is + * a submenu where the title is not visible. + * + */ +XPLM_API XPLMMenuID XPLMCreateMenu( + const char * inName, + XPLMMenuID inParentMenu, + int inParentItem, + XPLMMenuHandler_f inHandler, + void * inMenuRef); + +/* + * XPLMDestroyMenu + * + * This function destroys a menu that you have created. Use this to remove a + * submenu if necessary. (Normally this function will not be necessary.) + * + */ +XPLM_API void XPLMDestroyMenu( + XPLMMenuID inMenuID); + +/* + * XPLMClearAllMenuItems + * + * This function removes all menu items from a menu, allowing you to rebuild + * it. Use this function if you need to change the number of items on a menu. + * + */ +XPLM_API void XPLMClearAllMenuItems( + XPLMMenuID inMenuID); + +/* + * XPLMAppendMenuItem + * + * This routine appends a new menu item to the bottom of a menu and returns + * its index. Pass in the menu to add the item to, the items name, and a void + * * ref for this item. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + * Note that all menu indices returned are relative to your plugin's menus + * only; if your plugin creates two sub-menus in the Plugins menu at different + * times, it doesn't matter how many other plugins also create sub-menus of + * Plugins in the intervening time: your sub-menus will be given menu indices + * 0 and 1. (The SDK does some work in the back-end to filter out menus that + * are irrelevant to your plugin in order to deliver this consistency for each + * plugin.) + * + */ +XPLM_API int XPLMAppendMenuItem( + XPLMMenuID inMenu, + const char * inItemName, + void * inItemRef, + int inDeprecatedAndIgnored); + +#if defined(XPLM300) +/* + * XPLMAppendMenuItemWithCommand + * + * Like XPLMAppendMenuItem(), but instead of the new menu item triggering the + * XPLMMenuHandler_f of the containiner menu, it will simply execute the + * command you pass in. Using a command for your menu item allows the user to + * bind a keyboard shortcut to the command and see that shortcut represented + * in the menu. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + * Like XPLMAppendMenuItem(), all menu indices are relative to your plugin's + * menus only. + * + */ +XPLM_API int XPLMAppendMenuItemWithCommand( + XPLMMenuID inMenu, + const char * inItemName, + XPLMCommandRef inCommandToExecute); +#endif /* XPLM300 */ + +/* + * XPLMAppendMenuSeparator + * + * This routine adds a separator to the end of a menu. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + */ +XPLM_API void XPLMAppendMenuSeparator( + XPLMMenuID inMenu); + +/* + * XPLMSetMenuItemName + * + * This routine changes the name of an existing menu item. Pass in the menu + * ID and the index of the menu item. + * + */ +XPLM_API void XPLMSetMenuItemName( + XPLMMenuID inMenu, + int inIndex, + const char * inItemName, + int inDeprecatedAndIgnored); + +/* + * XPLMCheckMenuItem + * + * Set whether a menu item is checked. Pass in the menu ID and item index. + * + */ +XPLM_API void XPLMCheckMenuItem( + XPLMMenuID inMenu, + int index, + XPLMMenuCheck inCheck); + +/* + * XPLMCheckMenuItemState + * + * This routine returns whether a menu item is checked or not. A menu item's + * check mark may be on or off, or a menu may not have an icon at all. + * + */ +XPLM_API void XPLMCheckMenuItemState( + XPLMMenuID inMenu, + int index, + XPLMMenuCheck * outCheck); + +/* + * XPLMEnableMenuItem + * + * Sets whether this menu item is enabled. Items start out enabled. + * + */ +XPLM_API void XPLMEnableMenuItem( + XPLMMenuID inMenu, + int index, + int enabled); + +#if defined(XPLM210) +/* + * XPLMRemoveMenuItem + * + * Removes one item from a menu. Note that all menu items below are moved up + * one; your plugin must track the change in index numbers. + * + */ +XPLM_API void XPLMRemoveMenuItem( + XPLMMenuID inMenu, + int inIndex); +#endif /* XPLM210 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMNavigation.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMNavigation.h new file mode 100644 index 0000000..716caf0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMNavigation.h @@ -0,0 +1,362 @@ +#ifndef _XPLMNavigation_h_ +#define _XPLMNavigation_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMNavigation + ***************************************************************************/ +/* + * The XPLM Navigation APIs give you some access to the navigation databases + * inside X-Plane. X-Plane stores all navigation information in RAM, so by + * using these APIs you can gain access to most information without having to + * go to disk or parse the files yourself. + * + * You can also use this API to program the FMS. You must use the navigation + * APIs to find the nav-aids you want to program into the FMS, since the FMS + * is powered internally by X-Plane's navigation database. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * NAVIGATION DATABASE ACCESS + ***************************************************************************/ + +/* + * XPLMNavType + * + * These enumerations define the different types of navaids. They are each + * defined with a separate bit so that they may be bit-wise added together to + * form sets of nav-aid types. + * + * NOTE: xplm_Nav_LatLon is a specific lat-lon coordinate entered into the + * FMS. It will not exist in the database, and cannot be programmed into the + * FMS. Querying the FMS for navaids will return it. Use + * XPLMSetFMSEntryLatLon to set a lat/lon waypoint. + * + */ +enum { + xplm_Nav_Unknown = 0, + + xplm_Nav_Airport = 1, + + xplm_Nav_NDB = 2, + + xplm_Nav_VOR = 4, + + xplm_Nav_ILS = 8, + + xplm_Nav_Localizer = 16, + + xplm_Nav_GlideSlope = 32, + + xplm_Nav_OuterMarker = 64, + + xplm_Nav_MiddleMarker = 128, + + xplm_Nav_InnerMarker = 256, + + xplm_Nav_Fix = 512, + + xplm_Nav_DME = 1024, + + xplm_Nav_LatLon = 2048, + + +}; +typedef int XPLMNavType; + +/* + * XPLMNavRef + * + * XPLMNavRef is an iterator into the navigation database. The navigation + * database is essentially an array, but it is not necessarily densely + * populated. The only assumption you can safely make is that like-typed + * nav-aids are grouped together. + * + * Use XPLMNavRef to refer to a nav-aid. + * + * XPLM_NAV_NOT_FOUND is returned by functions that return an XPLMNavRef when + * the iterator must be invalid. + * + */ +typedef int XPLMNavRef; + +#define XPLM_NAV_NOT_FOUND -1 + +/* + * XPLMGetFirstNavAid + * + * This returns the very first navaid in the database. Use this to traverse + * the entire database. Returns XPLM_NAV_NOT_FOUND if the nav database is + * empty. + * + */ +XPLM_API XPLMNavRef XPLMGetFirstNavAid(void); + +/* + * XPLMGetNextNavAid + * + * Given a valid nav aid ref, this routine returns the next navaid. It + * returns XPLM_NAV_NOT_FOUND if the nav aid passed in was invalid or if the + * navaid passed in was the last one in the database. Use this routine to + * iterate across all like-typed navaids or the entire database. + * + */ +XPLM_API XPLMNavRef XPLMGetNextNavAid( + XPLMNavRef inNavAidRef); + +/* + * XPLMFindFirstNavAidOfType + * + * This routine returns the ref of the first navaid of the given type in the + * database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + * database. You must pass exactly one nav aid type to this routine. + * + */ +XPLM_API XPLMNavRef XPLMFindFirstNavAidOfType( + XPLMNavType inType); + +/* + * XPLMFindLastNavAidOfType + * + * This routine returns the ref of the last navaid of the given type in the + * database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + * database. You must pass exactly one nav aid type to this routine. + * + */ +XPLM_API XPLMNavRef XPLMFindLastNavAidOfType( + XPLMNavType inType); + +/* + * XPLMFindNavAid + * + * This routine provides a number of searching capabilities for the nav + * database. XPLMFindNavAid will search through every nav aid whose type is + * within inType (multiple types may be added together) and return any + * nav-aids found based on the following rules: + * + * * If inLat and inLon are not NULL, the navaid nearest to that lat/lon will + * be returned, otherwise the last navaid found will be returned. + * + * * If inFrequency is not NULL, then any navaids considered must match this + * frequency. Note that this will screen out radio beacons that do not have + * frequency data published (like inner markers) but not fixes and airports. + * + * * If inNameFragment is not NULL, only navaids that contain the fragment in + * their name will be returned. + * + * * If inIDFragment is not NULL, only navaids that contain the fragment in + * their IDs will be returned. + * + * This routine provides a simple way to do a number of useful searches: + * * Find the nearest navaid on this frequency. + * * Find the nearest airport. + * * Find the VOR whose ID is "KBOS". + * * Find the nearest airport whose name contains "Chicago". + * + */ +XPLM_API XPLMNavRef XPLMFindNavAid( + const char * inNameFragment, /* Can be NULL */ + const char * inIDFragment, /* Can be NULL */ + float * inLat, /* Can be NULL */ + float * inLon, /* Can be NULL */ + int * inFrequency, /* Can be NULL */ + XPLMNavType inType); + +/* + * XPLMGetNavAidInfo + * + * This routine returns information about a navaid. Any non-null field is + * filled out with information if it is available. + * + * Frequencies are in the nav.dat convention as described in the X-Plane nav + * database FAQ: NDB frequencies are exact, all others are multiplied by 100. + * + * The buffer for IDs should be at least 6 chars and the buffer for names + * should be at least 41 chars, but since these values are likely to go up, I + * recommend passing at least 32 chars for IDs and 256 chars for names when + * possible. + * + * The outReg parameter tells if the navaid is within the local "region" of + * loaded DSFs. (This information may not be particularly useful to plugins.) + * The parameter is a single byte value 1 for true or 0 for false, not a C + * string. + * + */ +XPLM_API void XPLMGetNavAidInfo( + XPLMNavRef inRef, + XPLMNavType * outType, /* Can be NULL */ + float * outLatitude, /* Can be NULL */ + float * outLongitude, /* Can be NULL */ + float * outHeight, /* Can be NULL */ + int * outFrequency, /* Can be NULL */ + float * outHeading, /* Can be NULL */ + char * outID, /* Can be NULL */ + char * outName, /* Can be NULL */ + char * outReg); /* Can be NULL */ + +/*************************************************************************** + * FLIGHT MANAGEMENT COMPUTER + ***************************************************************************/ +/* + * Note: the FMS works based on an array of entries. Indices into the array + * are zero-based. Each entry is a nav-aid plus an altitude. The FMS tracks + * the currently displayed entry and the entry that it is flying to. + * + * The FMS must be programmed with contiguous entries, so clearing an entry at + * the end shortens the effective flight plan. There is a max of 100 + * waypoints in the flight plan. + * + */ + + +/* + * XPLMCountFMSEntries + * + * This routine returns the number of entries in the FMS. + * + */ +XPLM_API int XPLMCountFMSEntries(void); + +/* + * XPLMGetDisplayedFMSEntry + * + * This routine returns the index of the entry the pilot is viewing. + * + */ +XPLM_API int XPLMGetDisplayedFMSEntry(void); + +/* + * XPLMGetDestinationFMSEntry + * + * This routine returns the index of the entry the FMS is flying to. + * + */ +XPLM_API int XPLMGetDestinationFMSEntry(void); + +/* + * XPLMSetDisplayedFMSEntry + * + * This routine changes which entry the FMS is showing to the index specified. + * + */ +XPLM_API void XPLMSetDisplayedFMSEntry( + int inIndex); + +/* + * XPLMSetDestinationFMSEntry + * + * This routine changes which entry the FMS is flying the aircraft toward. + * + */ +XPLM_API void XPLMSetDestinationFMSEntry( + int inIndex); + +/* + * XPLMGetFMSEntryInfo + * + * This routine returns information about a given FMS entry. If the entry is + * an airport or navaid, a reference to a nav entry can be returned allowing + * you to find additional information (such as a frequency, ILS heading, name, + * etc.). Note that this reference can be XPLM_NAV_NOT_FOUND until the + * information has been looked up asynchronously, so after flightplan changes, + * it might take up to a second for this field to become populated. The other + * information is available immediately. For a lat/lon entry, the lat/lon is + * returned by this routine but the navaid cannot be looked up (and the + * reference will be XPLM_NAV_NOT_FOUND). FMS name entry buffers should be at + * least 256 chars in length. + * + * WARNING: Due to a bug in X-Plane prior to 11.31, the navaid reference will + * not be set to XPLM_NAV_NOT_FOUND while no data is available, and instead + * just remain the value of the variable that you passed the pointer to. + * Therefore, always initialize the variable to XPLM_NAV_NOT_FOUND before + * passing the pointer to this function. + * + */ +XPLM_API void XPLMGetFMSEntryInfo( + int inIndex, + XPLMNavType * outType, /* Can be NULL */ + char * outID, /* Can be NULL */ + XPLMNavRef * outRef, /* Can be NULL */ + int * outAltitude, /* Can be NULL */ + float * outLat, /* Can be NULL */ + float * outLon); /* Can be NULL */ + +/* + * XPLMSetFMSEntryInfo + * + * This routine changes an entry in the FMS to have the destination navaid + * passed in and the altitude specified. Use this only for airports, fixes, + * and radio-beacon navaids. Currently of radio beacons, the FMS can only + * support VORs and NDBs. Use the routines below to clear or fly to a lat/lon. + * + */ +XPLM_API void XPLMSetFMSEntryInfo( + int inIndex, + XPLMNavRef inRef, + int inAltitude); + +/* + * XPLMSetFMSEntryLatLon + * + * This routine changes the entry in the FMS to a lat/lon entry with the given + * coordinates. + * + */ +XPLM_API void XPLMSetFMSEntryLatLon( + int inIndex, + float inLat, + float inLon, + int inAltitude); + +/* + * XPLMClearFMSEntry + * + * This routine clears the given entry, potentially shortening the flight + * plan. + * + */ +XPLM_API void XPLMClearFMSEntry( + int inIndex); + +/*************************************************************************** + * GPS RECEIVER + ***************************************************************************/ +/* + * These APIs let you read data from the GPS unit. + * + */ + +/* + * XPLMGetGPSDestinationType + * + * This routine returns the type of the currently selected GPS destination, + * one of fix, airport, VOR or NDB. + * + */ +XPLM_API XPLMNavType XPLMGetGPSDestinationType(void); + +/* + * XPLMGetGPSDestination + * + * This routine returns the current GPS destination. + * + */ +XPLM_API XPLMNavRef XPLMGetGPSDestination(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMPlanes.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMPlanes.h new file mode 100644 index 0000000..486302d --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMPlanes.h @@ -0,0 +1,287 @@ +#ifndef _XPLMPlanes_h_ +#define _XPLMPlanes_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMPlanes + ***************************************************************************/ +/* + * The XPLMPlanes APIs allow you to control the various aircraft in X-Plane, + * both the user's and the sim's. + * + * *Note*: unlike almost all other APIs in the SDK, aircraft paths are _full_ + * file system paths for historical reasons. You'll need to prefix all + * relative paths with the X-Plane path as accessed via XPLMGetSystemPath. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * USER AIRCRAFT ACCESS + ***************************************************************************/ + +/* + * XPLMSetUsersAircraft + * + * This routine changes the user's aircraft. Note that this will reinitialize + * the user to be on the nearest airport's first runway. Pass in a full path + * (hard drive and everything including the .acf extension) to the .acf file. + * + */ +XPLM_API void XPLMSetUsersAircraft( + const char * inAircraftPath); +/* + * XPLMPlaceUserAtAirport + * + * This routine places the user at a given airport. Specify the airport by + * its X-Plane airport ID (e.g. 'KBOS'). + * + */ +XPLM_API void XPLMPlaceUserAtAirport( + const char * inAirportCode); +#if defined(XPLM300) +/* + * XPLMPlaceUserAtLocation + * + * Places the user at a specific location after performing any necessary + * scenery loads. + * + * As with in-air starts initiated from the X-Plane user interface, the + * aircraft will always start with its engines running, regardless of the + * user's preferences (i.e., regardless of what the dataref + * `sim/operation/prefs/startup_running` says). + * + */ +XPLM_API void XPLMPlaceUserAtLocation( + double latitudeDegrees, + double longitudeDegrees, + float elevationMetersMSL, + float headingDegreesTrue, + float speedMetersPerSecond); +#endif /* XPLM300 */ +/*************************************************************************** + * GLOBAL AIRCRAFT ACCESS + ***************************************************************************/ + +/* The user's aircraft is always index 0. */ +#define XPLM_USER_AIRCRAFT 0 +#if defined(XPLM_DEPRECATED) +/* + * XPLMPlaneDrawState_t + * + * This structure contains additional plane parameter info to be passed to + * draw plane. Make sure to fill in the size of the structure field with + * sizeof(XPLMDrawPlaneState_t) so that the XPLM can tell how many fields you + * knew about when compiling your plugin (since more fields may be added + * later). + * + * Most of these fields are ratios from 0 to 1 for control input. X-Plane + * calculates what the actual controls look like based on the .acf file for + * that airplane. Note for the yoke inputs, this is what the pilot of the + * plane has commanded (post artificial stability system if there were one) + * and affects aelerons, rudder, etc. It is not necessarily related to the + * actual position of the plane! + * + */ +typedef struct { + /* The size of the draw state struct. */ + int structSize; + /* A ratio from [0..1] describing how far the landing gear is extended. */ + float gearPosition; + /* Ratio of flap deployment, 0 = up, 1 = full deploy. */ + float flapRatio; + /* Ratio of spoiler deployment, 0 = none, 1 = full deploy. */ + float spoilerRatio; + /* Ratio of speed brake deployment, 0 = none, 1 = full deploy. */ + float speedBrakeRatio; + /* Ratio of slat deployment, 0 = none, 1 = full deploy. */ + float slatRatio; + /* Wing sweep ratio, 0 = forward, 1 = swept. */ + float wingSweep; + /* Thrust power, 0 = none, 1 = full fwd, -1 = full reverse. */ + float thrust; + /* Total pitch input for this plane. */ + float yokePitch; + /* Total Heading input for this plane. */ + float yokeHeading; + /* Total Roll input for this plane. */ + float yokeRoll; +} XPLMPlaneDrawState_t; +#endif /* XPLM_DEPRECATED */ +/* + * XPLMCountAircraft + * + * This function returns the number of aircraft X-Plane is capable of having, + * as well as the number of aircraft that are currently active. These numbers + * count the user's aircraft. It can also return the plugin that is currently + * controlling aircraft. In X-Plane 7, this routine reflects the number of + * aircraft the user has enabled in the rendering options window. + * + */ +XPLM_API void XPLMCountAircraft( + int * outTotalAircraft, + int * outActiveAircraft, + XPLMPluginID * outController); +/* + * XPLMGetNthAircraftModel + * + * This function returns the aircraft model for the Nth aircraft. Indices are + * zero based, with zero being the user's aircraft. The file name should be + * at least 256 chars in length; the path should be at least 512 chars in + * length. + * + */ +XPLM_API void XPLMGetNthAircraftModel( + int inIndex, + char * outFileName, + char * outPath); +/*************************************************************************** + * EXCLUSIVE AIRCRAFT ACCESS + ***************************************************************************/ +/* + * The following routines require exclusive access to the airplane APIs. Only + * one plugin may have this access at a time. + * + */ + + +/* + * XPLMPlanesAvailable_f + * + * Your airplanes available callback is called when another plugin gives up + * access to the multiplayer planes. Use this to wait for access to + * multiplayer. + * + */ +typedef void (* XPLMPlanesAvailable_f)( + void * inRefcon); + +/* + * XPLMAcquirePlanes + * + * XPLMAcquirePlanes grants your plugin exclusive access to the aircraft. It + * returns 1 if you gain access, 0 if you do not. + * + * inAircraft - pass in an array of pointers to strings specifying the planes + * you want loaded. For any plane index you do not want loaded, pass a + * 0-length string. Other strings should be full paths with the .acf + * extension. NULL terminates this array, or pass NULL if there are no planes + * you want loaded. + * + * If you pass in a callback and do not receive access to the planes your + * callback will be called when the airplanes are available. If you do receive + * airplane access, your callback will not be called. + * + */ +XPLM_API int XPLMAcquirePlanes( + char ** inAircraft, /* Can be NULL */ + XPLMPlanesAvailable_f inCallback, + void * inRefcon); + +/* + * XPLMReleasePlanes + * + * Call this function to release access to the planes. Note that if you are + * disabled, access to planes is released for you and you must reacquire it. + * + */ +XPLM_API void XPLMReleasePlanes(void); + +/* + * XPLMSetActiveAircraftCount + * + * This routine sets the number of active planes. If you pass in a number + * higher than the total number of planes availables, only the total number of + * planes available is actually used. + * + */ +XPLM_API void XPLMSetActiveAircraftCount( + int inCount); + +/* + * XPLMSetAircraftModel + * + * This routine loads an aircraft model. It may only be called if you have + * exclusive access to the airplane APIs. Pass in the path of the model with + * the .acf extension. The index is zero based, but you may not pass in 0 + * (use XPLMSetUsersAircraft to load the user's aircracft). + * + */ +XPLM_API void XPLMSetAircraftModel( + int inIndex, + const char * inAircraftPath); + +/* + * XPLMDisableAIForPlane + * + * This routine turns off X-Plane's AI for a given plane. The plane will + * continue to draw and be a real plane in X-Plane, but will not move itself. + * + */ +XPLM_API void XPLMDisableAIForPlane( + int inPlaneIndex); + +#if defined(XPLM_DEPRECATED) +/* + * XPLMDrawAircraft + * + * WARNING: Aircraft drawing via this API is deprecated and will not work in + * future versions of X-Plane. Use XPLMInstance for 3-d drawing of custom + * aircraft models. + * + * This routine draws an aircraft. It can only be called from a 3-d drawing + * callback. Pass in the position of the plane in OpenGL local coordinates + * and the orientation of the plane. A 1 for full drawing indicates that the + * whole plane must be drawn; a 0 indicates you only need the nav lights + * drawn. (This saves rendering time when planes are far away.) + * + */ +XPLM_API void XPLMDrawAircraft( + int inPlaneIndex, + float inX, + float inY, + float inZ, + float inPitch, + float inRoll, + float inYaw, + int inFullDraw, + XPLMPlaneDrawState_t * inDrawStateInfo); +#endif /* XPLM_DEPRECATED */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMReinitUsersPlane + * + * WARNING: DO NOT USE. Use XPLMPlaceUserAtAirport or + * XPLMPlaceUserAtLocation. + * + * This function recomputes the derived flight model data from the aircraft + * structure in memory. If you have used the data access layer to modify the + * aircraft structure, use this routine to resynchronize X-Plane; since + * X-Plane works at least partly from derived values, the sim will not behave + * properly until this is called. + * + * WARNING: this routine does not necessarily place the airplane at the + * airport; use XPLMSetUsersAircraft to be compatible. This routine is + * provided to do special experimentation with flight models without resetting + * flight. + * + */ +XPLM_API void XPLMReinitUsersPlane(void); +#endif /* XPLM_DEPRECATED */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMPlugin.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMPlugin.h new file mode 100644 index 0000000..be5d06c --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMPlugin.h @@ -0,0 +1,422 @@ +#ifndef _XPLMPlugin_h_ +#define _XPLMPlugin_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMPlugin + ***************************************************************************/ +/* + * These APIs provide facilities to find and work with other plugins and + * manage other plugins. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FINDING PLUGINS + ***************************************************************************/ +/* + * These APIs allow you to find another plugin or yourself, or iterate across + * all plugins. For example, if you wrote an FMS plugin that needed to talk + * to an autopilot plugin, you could use these APIs to locate the autopilot + * plugin. + * + */ + + +/* + * XPLMGetMyID + * + * This routine returns the plugin ID of the calling plug-in. Call this to + * get your own ID. + * + */ +XPLM_API XPLMPluginID XPLMGetMyID(void); + +/* + * XPLMCountPlugins + * + * This routine returns the total number of plug-ins that are loaded, both + * disabled and enabled. + * + */ +XPLM_API int XPLMCountPlugins(void); + +/* + * XPLMGetNthPlugin + * + * This routine returns the ID of a plug-in by index. Index is 0 based from 0 + * to XPLMCountPlugins-1, inclusive. Plugins may be returned in any arbitrary + * order. + * + */ +XPLM_API XPLMPluginID XPLMGetNthPlugin( + int inIndex); + +/* + * XPLMFindPluginByPath + * + * This routine returns the plug-in ID of the plug-in whose file exists at the + * passed in absolute file system path. XPLM_NO_PLUGIN_ID is returned if the + * path does not point to a currently loaded plug-in. + * + */ +XPLM_API XPLMPluginID XPLMFindPluginByPath( + const char * inPath); + +/* + * XPLMFindPluginBySignature + * + * This routine returns the plug-in ID of the plug-in whose signature matches + * what is passed in or XPLM_NO_PLUGIN_ID if no running plug-in has this + * signature. Signatures are the best way to identify another plug-in as they + * are independent of the file system path of a plug-in or the human-readable + * plug-in name, and should be unique for all plug-ins. Use this routine to + * locate another plugin that your plugin interoperates with + * + */ +XPLM_API XPLMPluginID XPLMFindPluginBySignature( + const char * inSignature); + +/* + * XPLMGetPluginInfo + * + * This routine returns information about a plug-in. Each parameter should be + * a pointer to a buffer of at least + * 256 characters, or NULL to not receive the information. + * + * outName - the human-readable name of the plug-in. outFilePath - the + * absolute file path to the file that contains this plug-in. outSignature - a + * unique string that identifies this plug-in. outDescription - a + * human-readable description of this plug-in. + * + */ +XPLM_API void XPLMGetPluginInfo( + XPLMPluginID inPlugin, + char * outName, /* Can be NULL */ + char * outFilePath, /* Can be NULL */ + char * outSignature, /* Can be NULL */ + char * outDescription); /* Can be NULL */ + +/*************************************************************************** + * ENABLING/DISABLING PLUG-INS + ***************************************************************************/ +/* + * These routines are used to work with plug-ins and manage them. Most + * plugins will not need to use these APIs. + * + */ + + +/* + * XPLMIsPluginEnabled + * + * Returns whether the specified plug-in is enabled for running. + * + */ +XPLM_API int XPLMIsPluginEnabled( + XPLMPluginID inPluginID); + +/* + * XPLMEnablePlugin + * + * This routine enables a plug-in if it is not already enabled. It returns 1 + * if the plugin was enabled or successfully enables itself, 0 if it does not. + * Plugins may fail to enable (for example, if resources cannot be acquired) + * by returning 0 from their XPluginEnable callback. + * + */ +XPLM_API int XPLMEnablePlugin( + XPLMPluginID inPluginID); + +/* + * XPLMDisablePlugin + * + * This routine disableds an enabled plug-in. + * + */ +XPLM_API void XPLMDisablePlugin( + XPLMPluginID inPluginID); + +/* + * XPLMReloadPlugins + * + * This routine reloads all plug-ins. Once this routine is called and you + * return from the callback you were within (e.g. a menu select callback) you + * will receive your XPluginDisable and XPluginStop callbacks and your DLL + * will be unloaded, then the start process happens as if the sim was starting + * up. + * + */ +XPLM_API void XPLMReloadPlugins(void); + +/*************************************************************************** + * INTERPLUGIN MESSAGING + ***************************************************************************/ +/* + * Plugin messages are defined as 32-bit integers. Messages below 0x00FFFFFF + * are reserved for X-Plane and the plugin SDK. + * + * Messages come with a pointer parameter; the meaning of this pointer depends + * on the message itself. In some messages, the pointer parameter contains an + * actual typed pointer to data that can be inspected in the plugin; in these + * cases the documentation will state that the parameter "points to" + * information. + * + * in other cases, the value of the pointer is actually an integral number + * stuffed into the pointer's storage. In these second cases, the pointer + * parameter needs to be cast, not dereferenced. In these caess, the + * documentation will state that the parameter "contains" a value, which will + * always be an integral type. + * + * Some messages don't use the pointer parameter - in this case your plugin + * should ignore it. + * + * Messages have two conceptual uses: notifications and commands. Commands + * are sent from one plugin to another to induce behavior; notifications are + * sent from one plugin to all others for informational purposes. It is + * important that commands and notifications not have the same values because + * this could cause a notification sent by one plugin to accidentally induce a + * command in another. + * + * By convention, plugin-defined notifications should have the high bit set + * (e.g. be greater or equal to unsigned 0x8000000) while commands should have + * this bit be cleared. + * + * The following messages are sent to your plugin by X-Plane. + * + */ + + +/* This message is sent to your plugin whenever the user's plane crashes. The * + * parameter is ignored. */ +#define XPLM_MSG_PLANE_CRASHED 101 + +/* This message is sent to your plugin whenever a new plane is loaded. The * + * parameter contains the index number of the plane being loaded; 0 indicates * + * the user's plane. */ +#define XPLM_MSG_PLANE_LOADED 102 + +/* This messages is sent whenever the user's plane is positioned at a new * + * airport. The parameter is ignored. */ +#define XPLM_MSG_AIRPORT_LOADED 103 + +/* This message is sent whenever new scenery is loaded. Use datarefs to * + * determine the new scenery files that were loaded. The parameter is ignored.*/ +#define XPLM_MSG_SCENERY_LOADED 104 + +/* This message is sent whenever the user adjusts the number of X-Plane * + * aircraft models. You must use XPLMCountPlanes to find out how many planes * + * are now available. This message will only be sent in XP7 and higher * + * because in XP6 the number of aircraft is not user-adjustable. The parameter* + * is ignored. */ +#define XPLM_MSG_AIRPLANE_COUNT_CHANGED 105 + +#if defined(XPLM200) +/* This message is sent to your plugin whenever a plane is unloaded. The * + * parameter contains the index number of the plane being unloaded; 0 * + * indicates the user's plane. The parameter is of type int, passed as the * + * value of the pointer. (That is: the parameter is an int, not a pointer to * + * an int.) */ +#define XPLM_MSG_PLANE_UNLOADED 106 +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* This message is sent to your plugin right before X-Plane writes its * + * preferences file. You can use this for two purposes: to write your own * + * preferences, and to modify any datarefs to influence preferences output. * + * For example, if your plugin temporarily modifies saved preferences, you can* + * put them back to their default values here to avoid having the tweaks be * + * persisted if your plugin is not loaded on the next invocation of X-Plane. * + * The parameter is ignored. */ +#define XPLM_MSG_WILL_WRITE_PREFS 107 +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* This message is sent to your plugin right after a livery is loaded for an * + * airplane. You can use this to check the new livery (via datarefs) and * + * react accordingly. The parameter contains the index number of the aircraft* + * whose livery is changing. */ +#define XPLM_MSG_LIVERY_LOADED 108 +#endif /* XPLM210 */ + +#if defined(XPLM301) +/* Sent to your plugin right before X-Plane enters virtual reality mode (at * + * which time any windows that are not positioned in VR mode will no longer be* + * visible to the user). The parameter is unused and should be ignored. */ +#define XPLM_MSG_ENTERED_VR 109 +#endif /* XPLM301 */ + +#if defined(XPLM301) +/* Sent to your plugin right before X-Plane leaves virtual reality mode (at * + * which time you may want to clean up windows that are positioned in VR * + * mode). The parameter is unused and should be ignored. */ +#define XPLM_MSG_EXITING_VR 110 +#endif /* XPLM301 */ + +#if defined(XPLM303) +/* Sent to your plugin if another plugin wants to take over AI planes. If you * + * are a synthetic traffic provider, that probably means a plugin for an * + * online network has connected and wants to supply aircraft flown by real * + * humans and you should cease to provide synthetic traffic. If however you * + * are providing online traffic from real humans, you probably don't want to * + * disconnect, in which case you just ignore this message. The sender is the * + * plugin ID of the plugin asking for control of the planes now. You can use * + * it to find out who is requesting and whether you should yield to them. * + * Synthetic traffic providers should always yield to online networks. The * + * parameter is unused and should be ignored. */ +#define XPLM_MSG_RELEASE_PLANES 111 +#endif /* XPLM303 */ + +/* + * XPLMSendMessageToPlugin + * + * This function sends a message to another plug-in or X-Plane. Pass + * XPLM_NO_PLUGIN_ID to broadcast to all plug-ins. Only enabled plug-ins with + * a message receive function receive the message. + * + */ +XPLM_API void XPLMSendMessageToPlugin( + XPLMPluginID inPlugin, + int inMessage, + void * inParam); + +#if defined(XPLM200) +/*************************************************************************** + * Plugin Features API + ***************************************************************************/ +/* + * The plugin features API allows your plugin to "sign up" for additional + * capabilities and plugin system features that are normally disabled for + * backward compatibility. This allows advanced plugins to "opt-in" to new + * behavior. + * + * Each feature is defined by a permanent string name. The feature string + * names will vary with the particular installation of X-Plane, so plugins + * should not expect a feature to be guaranteed present. + * + * XPLM_WANTS_REFLECTIONS + * ---------------------- + * + * Available in the SDK 2.0 and later for X-Plane 9, enabling this capability + * causes your plugin to receive drawing hook callbacks when X-Plane builds + * its off-screen reflection and shadow rendering passes. Plugins should + * enable this and examine the dataref sim/graphics/view/plane_render_type to + * determine whether the drawing callback is for a reflection, shadow + * calculation, or the main screen. Rendering can be simlified or omitted for + * reflections, and non-solid drawing should be skipped for shadow + * calculations. + * + * **Note**: direct drawing via draw callbacks is not recommended; use the + * XPLMInstance API to create object models instead. + * + * XPLM_USE_NATIVE_PATHS + * --------------------- + * + * available in the SDK 2.1 and later for X-Plane 10, this modifies the plugin + * system to use Unix-style paths on all operating systems. With this enabled: + * + * * OS X paths will match the native OS X Unix. + * * Windows will use forward slashes but preserve C:\ or another drive letter + * when using complete file paths. + * * Linux uses its native file system path scheme. + * + * Without this enabled: + * + * * OS X will use CFM file paths separated by a colon. + * * Windows will use back-slashes and conventional DOS paths. + * * Linux uses its native file system path scheme. + * + * All plugins should enable this feature on OS X to access the native file + * system. + * + * XPLM_USE_NATIVE_WIDGET_WINDOWS + * ------------------------------ + * + * Available in the SDK 3.0.2 SDK, this capability tells the widgets library + * to use new, modern X-Plane backed XPLMDisplay windows to anchor all widget + * trees. Without it, widgets will always use legacy windows. + * + * Plugins should enable this to allow their widget hierarchies to respond to + * the user's UI size settings and to map widget-based windwos to a VR HMD. + * + * Before enabling this, make sure any custom widget code in your plugin is + * prepared to cope with the UI coordinate system not being th same as the + * OpenGL window coordinate system. + * + */ + + +/* + * XPLMFeatureEnumerator_f + * + * You pass an XPLMFeatureEnumerator_f to get a list of all features supported + * by a given version running version of X-Plane. This routine is called once + * for each feature. + * + */ +typedef void (* XPLMFeatureEnumerator_f)( + const char * inFeature, + void * inRef); + +/* + * XPLMHasFeature + * + * This returns 1 if the given installation of X-Plane supports a feature, or + * 0 if it does not. + * + */ +XPLM_API int XPLMHasFeature( + const char * inFeature); + +/* + * XPLMIsFeatureEnabled + * + * This returns 1 if a feature is currently enabled for your plugin, or 0 if + * it is not enabled. It is an error to call this routine with an unsupported + * feature. + * + */ +XPLM_API int XPLMIsFeatureEnabled( + const char * inFeature); + +/* + * XPLMEnableFeature + * + * This routine enables or disables a feature for your plugin. This will + * change the running behavior of X-Plane and your plugin in some way, + * depending on the feature. + * + */ +XPLM_API void XPLMEnableFeature( + const char * inFeature, + int inEnable); + +/* + * XPLMEnumerateFeatures + * + * This routine calls your enumerator callback once for each feature that this + * running version of X-Plane supports. Use this routine to determine all of + * the features that X-Plane can support. + * + */ +XPLM_API void XPLMEnumerateFeatures( + XPLMFeatureEnumerator_f inEnumerator, + void * inRef); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMProcessing.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMProcessing.h new file mode 100644 index 0000000..94ef0c4 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMProcessing.h @@ -0,0 +1,264 @@ +#ifndef _XPLMProcessing_h_ +#define _XPLMProcessing_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMProcessing + ***************************************************************************/ +/* + * This API allows you to get regular callbacks during the flight loop, the + * part of X-Plane where the plane's position calculates the physics of + * flight, etc. Use these APIs to accomplish periodic tasks like logging data + * and performing I/O. + * + * You can receive a callback either just before or just after the per-frame + * physics calculations happen - you can use post-FM callbacks to "patch" the + * flight model after it has run. + * + * If the user has set the number of flight model iterations per frame greater + * than one your plugin will _not_ see this; these integrations run on the + * sub-section of the flight model where iterations improve responsiveness + * (e.g. physical integration, not simple systems tracking) and are thus + * opaque to plugins. + * + * Flight loop scheduling, when scheduled by time, is scheduled by a "first + * callback after the deadline" schedule, e.g. your callbacks will always be + * slightly late to ensure that we don't run faster than your deadline. + * + * WARNING: Do NOT use these callbacks to draw! You cannot draw during flight + * loop callbacks. Use the drawing callbacks (see XPLMDisplay for more info) + * for graphics. (One exception: you can use a post-flight loop callback to + * update your own off-screen FBOs.) + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FLIGHT LOOP CALLBACKS + ***************************************************************************/ + +#if defined(XPLM210) +/* + * XPLMFlightLoopPhaseType + * + * You can register a flight loop callback to run either before or after the + * flight model is integrated by X-Plane. + * + */ +enum { + /* Your callback runs before X-Plane integrates the flight model. */ + xplm_FlightLoop_Phase_BeforeFlightModel = 0, + + /* Your callback runs after X-Plane integrates the flight model. */ + xplm_FlightLoop_Phase_AfterFlightModel = 1, + + +}; +typedef int XPLMFlightLoopPhaseType; +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMFlightLoopID + * + * This is an opaque identifier for a flight loop callback. You can use this + * identifier to easily track and remove your callbacks, or to use the new + * flight loop APIs. + * + */ +typedef void * XPLMFlightLoopID; +#endif /* XPLM210 */ + +/* + * XPLMFlightLoop_f + * + * This is your flight loop callback. Each time the flight loop is iterated + * through, you receive this call at the end. + * + * Flight loop callbacks receive a number of input timing parameters. These + * input timing parameters are not particularly useful; you may need to track + * your own timing data (e.g. by reading datarefs). The input parameters are: + * + * - inElapsedSinceLastCall: the wall time since your last callback. + * - inElapsedTimeSinceLastFlightLoop: the wall time since any flight loop was + * dispatched. + * - inCounter: a monotonically increasing counter, bumped once per flight + * loop dispatch from the sim. + * - inRefcon: your own ptr constant from when you regitered yor callback. + * + * Your return value controls when you will next be called. + * + * - Return 0 to stop receiving callbacks. + * - Pass a positive number to specify how many seconds until the next + * callback. (You will be called at or after this time, not before.) + * - Pass a negative number to specify how many loops must go by until you + * are called. For example, -1.0 means call me the very next loop. + * + * Try to run your flight loop as infrequently as is practical, and suspend it + * (using return value 0) when you do not need it; lots of flight loop + * callbacks that do nothing lowers X-Plane's frame rate. + * + * Your callback will NOT be unregistered if you return 0; it will merely be + * inactive. + * + */ +typedef float (* XPLMFlightLoop_f)( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon); + +#if defined(XPLM210) +/* + * XPLMCreateFlightLoop_t + * + * XPLMCreateFlightLoop_t contains the parameters to create a new flight loop + * callback. The strsucture can be expanded in future SDKs - always set + * structSize to the size of your structure in bytes. + * + */ +typedef struct { + int structSize; + XPLMFlightLoopPhaseType phase; + XPLMFlightLoop_f callbackFunc; + void * refcon; +} XPLMCreateFlightLoop_t; +#endif /* XPLM210 */ + +/* + * XPLMGetElapsedTime + * + * This routine returns the elapsed time since the sim started up in decimal + * seconds. This is a wall timer; it keeps counting upward even if the sim is + * pasued. + * + * __WARNING__: XPLMGetElapsedTime is not a very good timer! It lacks + * precision in both its data type and its source. Do not attempt to use it + * for timing critical applications like network multiplayer. + * + */ +XPLM_API float XPLMGetElapsedTime(void); + +/* + * XPLMGetCycleNumber + * + * This routine returns a counter starting at zero for each sim cycle + * computed/video frame rendered. + * + */ +XPLM_API int XPLMGetCycleNumber(void); + +/* + * XPLMRegisterFlightLoopCallback + * + * This routine registers your flight loop callback. Pass in a pointer to a + * flight loop function and a refcon. inInterval defines when you will be + * called. Pass in a positive number to specify seconds from registration time + * to the next callback. Pass in a negative number to indicate when you will + * be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to not be + * called; your callback will be inactive. + * + * (This legacy function only installs pre-flight-loop callbacks; use + * XPLMCreateFlightLoop for more control.) + * + */ +XPLM_API void XPLMRegisterFlightLoopCallback( + XPLMFlightLoop_f inFlightLoop, + float inInterval, + void * inRefcon); + +/* + * XPLMUnregisterFlightLoopCallback + * + * This routine unregisters your flight loop callback. Do NOT call it from + * your flight loop callback. Once your flight loop callback is unregistered, + * it will not be called again. + * + * Only use this on flight loops registered via + * XPLMRegisterFlightLoopCallback. + * + */ +XPLM_API void XPLMUnregisterFlightLoopCallback( + XPLMFlightLoop_f inFlightLoop, + void * inRefcon); + +/* + * XPLMSetFlightLoopCallbackInterval + * + * This routine sets when a callback will be called. Do NOT call it from your + * callback; use the return value of the callback to change your callback + * interval from inside your callback. + * + * inInterval is formatted the same way as in XPLMRegisterFlightLoopCallback; + * positive for seconds, negative for cycles, and 0 for deactivating the + * callback. If inRelativeToNow is 1, times are from the time of this call; + * otherwise they are from the time the callback was last called (or the time + * it was registered if it has never been called. + * + */ +XPLM_API void XPLMSetFlightLoopCallbackInterval( + XPLMFlightLoop_f inFlightLoop, + float inInterval, + int inRelativeToNow, + void * inRefcon); + +#if defined(XPLM210) +/* + * XPLMCreateFlightLoop + * + * This routine creates a flight loop callback and returns its ID. The flight + * loop callback is created using the input param struct, and is inited to be + * unscheduled. + * + */ +XPLM_API XPLMFlightLoopID XPLMCreateFlightLoop( + XPLMCreateFlightLoop_t * inParams); +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMDestroyFlightLoop + * + * This routine destroys a flight loop callback by ID. Only call it on flight + * loops created with the newer XPLMCreateFlightLoop API. + * + */ +XPLM_API void XPLMDestroyFlightLoop( + XPLMFlightLoopID inFlightLoopID); +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMScheduleFlightLoop + * + * This routine schedules a flight loop callback for future execution. If + * inInterval is negative, it is run in a certain number of frames based on + * the absolute value of the input. If the interval is positive, it is a + * duration in seconds. + * + * If inRelativeToNow is true, ties are interpretted relative to the time this + * routine is called; otherwise they are relative to the last call time or the + * time the flight loop was registered (if never called). + * + */ +XPLM_API void XPLMScheduleFlightLoop( + XPLMFlightLoopID inFlightLoopID, + float inInterval, + int inRelativeToNow); +#endif /* XPLM210 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMScenery.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMScenery.h new file mode 100644 index 0000000..452bac9 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMScenery.h @@ -0,0 +1,450 @@ +#ifndef _XPLMScenery_h_ +#define _XPLMScenery_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMScenery + ***************************************************************************/ +/* + * This package contains APIs to interact with X-Plane's scenery system. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XPLM200) +/*************************************************************************** + * Terrain Y-Testing + ***************************************************************************/ +/* + * The Y-testing API allows you to locate the physical scenery mesh. This + * would be used to place dynamic graphics on top of the ground in a plausible + * way or do physics interactions. + * + * The Y-test API works via probe objects, which are allocated by your plugin + * and used to query terrain. Probe objects exist both to capture which + * algorithm you have requested (see probe types) and also to cache query + * information. + * + * Performance Guidelines + * ---------------------- + * + * It is generally faster to use the same probe for nearby points and + * different probes for different points. Try not to allocate more than + * "hundreds" of probes at most. Share probes if you need more. Generally, + * probing operations are expensive, and should be avoided via caching when + * possible. + * + * Y testing returns a location on the terrain, a normal vectory, and a + * velocity vector. The normal vector tells you the slope of the terrain at + * that point. The velocity vector tells you if that terrain is moving (and is + * in meters/second). For example, if your Y test hits the aircraft carrier + * deck, this tells you the velocity of that point on the deck. + * + * Note: the Y-testing API is limited to probing the loaded scenery area, + * which is approximately 300x300 km in X-Plane 9. Probes outside this area + * will return the height of a 0 MSL sphere. + * + */ + + +/* + * XPLMProbeType + * + * XPLMProbeType defines the type of terrain probe - each probe has a + * different algorithm. (Only one type of probe is provided right now, but + * future APIs will expose more flexible or poewrful or useful probes. + * + */ +enum { + /* The Y probe gives you the location of the tallest physical scenery along * + * the Y axis going through the queried point. */ + xplm_ProbeY = 0, + + +}; +typedef int XPLMProbeType; + +/* + * XPLMProbeResult + * + * Probe results - possible results from a probe query. + * + */ +enum { + /* The probe hit terrain and returned valid values. */ + xplm_ProbeHitTerrain = 0, + + /* An error in the API call. Either the probe struct size is bad, or the * + * probe is invalid or the type is mismatched for the specific query call. */ + xplm_ProbeError = 1, + + /* The probe call succeeded but there is no terrain under this point (perhaps * + * it is off the side of the planet?) */ + xplm_ProbeMissed = 2, + + +}; +typedef int XPLMProbeResult; + +/* + * XPLMProbeRef + * + * An XPLMProbeRef is an opaque handle to a probe, used for querying the + * terrain. + * + */ +typedef void * XPLMProbeRef; + +/* + * XPLMProbeInfo_t + * + * XPLMProbeInfo_t contains the results of a probe call. Make sure to set + * structSize to the size of the struct before using it. + * + */ +typedef struct { + /* Size of structure in bytes - always set this before calling the XPLM. */ + int structSize; + /* Resulting X location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationX; + /* Resulting Y location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationY; + /* Resulting Z location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationZ; + /* X component of the normal vector to the terrain we found. */ + float normalX; + /* Y component of the normal vector to the terrain we found. */ + float normalY; + /* Z component of the normal vector to the terrain we found. */ + float normalZ; + /* X component of the velocity vector of the terrain we found. */ + float velocityX; + /* Y component of the velocity vector of the terrain we found. */ + float velocityY; + /* Z component of the velocity vector of the terrain we found. */ + float velocityZ; + /* Tells if the surface we hit is water (otherwise it is land). */ + int is_wet; +} XPLMProbeInfo_t; + +/* + * XPLMCreateProbe + * + * Creates a new probe object of a given type and returns. + * + */ +XPLM_API XPLMProbeRef XPLMCreateProbe( + XPLMProbeType inProbeType); + +/* + * XPLMDestroyProbe + * + * Deallocates an existing probe object. + * + */ +XPLM_API void XPLMDestroyProbe( + XPLMProbeRef inProbe); + +/* + * XPLMProbeTerrainXYZ + * + * Probes the terrain. Pass in the XYZ coordinate of the probe point, a probe + * object, and an XPLMProbeInfo_t struct that has its structSize member set + * properly. Other fields are filled in if we hit terrain, and a probe result + * is returned. + * + */ +XPLM_API XPLMProbeResult XPLMProbeTerrainXYZ( + XPLMProbeRef inProbe, + float inX, + float inY, + float inZ, + XPLMProbeInfo_t * outInfo); + +#endif /* XPLM200 */ +#if defined(XPLM300) +/*************************************************************************** + * Magnetic Variation + ***************************************************************************/ +/* + * Use the magnetic variation (more properly, the "magnetic declination") API + * to find the offset of magnetic north from true north at a given latitude + * and longitude within the simulator. + * + * In the real world, the Earth's magnetic field is irregular, such that true + * north (the direction along a meridian toward the north pole) does not + * necessarily match what a magnetic compass shows as north. + * + * Using this API ensures that you present the same offsets to users as + * X-Plane's built-in instruments. + * + */ + + +/* + * XPLMGetMagneticVariation + * + * Returns X-Plane's simulated magnetic variation (declination) at the + * indication latitude and longitude. + * + */ +XPLM_API float XPLMGetMagneticVariation( + double latitude, + double longitude); + +/* + * XPLMDegTrueToDegMagnetic + * + * Converts a heading in degrees relative to true north into a value relative + * to magnetic north at the user's current location. + * + */ +XPLM_API float XPLMDegTrueToDegMagnetic( + float headingDegreesTrue); + +/* + * XPLMDegMagneticToDegTrue + * + * Converts a heading in degrees relative to magnetic north at the user's + * current location into a value relative to true north. + * + */ +XPLM_API float XPLMDegMagneticToDegTrue( + float headingDegreesMagnetic); + +#endif /* XPLM300 */ +/*************************************************************************** + * Object Drawing + ***************************************************************************/ +/* + * The object drawing routines let you load and draw X-Plane OBJ files. + * Objects are loaded by file path and managed via an opaque handle. X-Plane + * naturally reference counts objects, so it is important that you balance + * every successful call to XPLMLoadObject with a call to XPLMUnloadObject! + * + */ + + +#if defined(XPLM200) +/* + * XPLMObjectRef + * + * An XPLMObjectRef is a opaque handle to an .obj file that has been loaded + * into memory. + * + */ +typedef void * XPLMObjectRef; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMDrawInfo_t + * + * The XPLMDrawInfo_t structure contains positioning info for one object that + * is to be drawn. Be sure to set structSize to the size of the structure for + * future expansion. + * + */ +typedef struct { + /* Set this to the size of this structure! */ + int structSize; + /* X location of the object in local coordinates. */ + float x; + /* Y location of the object in local coordinates. */ + float y; + /* Z location of the object in local coordinates. */ + float z; + /* Pitch in degres to rotate the object, positive is up. */ + float pitch; + /* Heading in local coordinates to rotate the object, clockwise. */ + float heading; + /* Roll to rotate the object. */ + float roll; +} XPLMDrawInfo_t; +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* + * XPLMObjectLoaded_f + * + * You provide this callback when loading an object asynchronously; it will be + * called once the object is loaded. Your refcon is passed back. The object + * ref passed in is the newly loaded object (ready for use) or NULL if an + * error occured. + * + * If your plugin is disabled, this callback will be delivered as soon as the + * plugin is re-enabled. If your plugin is unloaded before this callback is + * ever called, the SDK will release the object handle for you. + * + */ +typedef void (* XPLMObjectLoaded_f)( + XPLMObjectRef inObject, + void * inRefcon); +#endif /* XPLM210 */ + +#if defined(XPLM200) +/* + * XPLMLoadObject + * + * This routine loads an OBJ file and returns a handle to it. If X-Plane has + * already loaded the object, the handle to the existing object is returned. + * Do not assume you will get the same handle back twice, but do make sure to + * call unload once for every load to avoid "leaking" objects. The object will + * be purged from memory when no plugins and no scenery are using it. + * + * The path for the object must be relative to the X-System base folder. If + * the path is in the root of the X-System folder you may need to prepend ./ + * to it; loading objects in the root of the X-System folder is STRONGLY + * discouraged - your plugin should not dump art resources in the root folder! + * + * XPLMLoadObject will return NULL if the object cannot be loaded (either + * because it is not found or the file is misformatted). This routine will + * load any object that can be used in the X-Plane scenery system. + * + * It is important that the datarefs an object uses for animation already be + * loaded before you load the object. For this reason it may be necessary to + * defer object loading until the sim has fully started. + * + */ +XPLM_API XPLMObjectRef XPLMLoadObject( + const char * inPath); +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* + * XPLMLoadObjectAsync + * + * This routine loads an object asynchronously; control is returned to you + * immediately while X-Plane loads the object. The sim will not stop flying + * while the object loads. For large objects, it may be several seconds before + * the load finishes. + * + * You provide a callback function that is called once the load has completed. + * Note that if the object cannot be loaded, you will not find out until the + * callback function is called with a NULL object handle. + * + * There is no way to cancel an asynchronous object load; you must wait for + * the load to complete and then release the object if it is no longer + * desired. + * + */ +XPLM_API void XPLMLoadObjectAsync( + const char * inPath, + XPLMObjectLoaded_f inCallback, + void * inRefcon); +#endif /* XPLM210 */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMDrawObjects + * + * __Deprecation Warning__: use XPLMInstancing to draw 3-d objects by creating + * instances, rather than these APIs from draw callbacks. + * + * XPLMDrawObjects draws an object from an OBJ file one or more times. You + * pass in the object and an array of XPLMDrawInfo_t structs, one for each + * place you would like the object to be drawn. + * + * X-Plane will attempt to cull the objects based on LOD and visibility, and + * will pick the appropriate LOD. + * + * Lighting is a boolean; pass 1 to show the night version of object with + * night-only lights lit up. Pass 0 to show the daytime version of the object. + * + * earth_relative controls the coordinate system. If this is 1, the rotations + * you specify are applied to the object after its coordinate system is + * transformed from local to earth-relative coordinates -- that is, an object + * with no rotations will point toward true north and the Y axis will be up + * against gravity. If this is 0, the object is drawn with your rotations from + * local coordanates -- that is, an object with no rotations is drawn pointing + * down the -Z axis and the Y axis of the object matches the local coordinate + * Y axis. + * + */ +XPLM_API void XPLMDrawObjects( + XPLMObjectRef inObject, + int inCount, + XPLMDrawInfo_t * inLocations, + int lighting, + int earth_relative); +#endif /* XPLM_DEPRECATED */ + +#if defined(XPLM200) +/* + * XPLMUnloadObject + * + * This routine marks an object as no longer being used by your plugin. + * Objects are reference counted: once no plugins are using an object, it is + * purged from memory. Make sure to call XPLMUnloadObject once for each + * successful call to XPLMLoadObject. + * + */ +XPLM_API void XPLMUnloadObject( + XPLMObjectRef inObject); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/*************************************************************************** + * Library Access + ***************************************************************************/ +/* + * The library access routines allow you to locate scenery objects via the + * X-Plane library system. Right now library access is only provided for + * objects, allowing plugin-drawn objects to be extended using the library + * system. + * + */ + + +/* + * XPLMLibraryEnumerator_f + * + * An XPLMLibraryEnumerator_f is a callback you provide that is called once + * for each library element that is located. The returned paths will be + * relative to the X-System folder. + * + */ +typedef void (* XPLMLibraryEnumerator_f)( + const char * inFilePath, + void * inRef); + +/* + * XPLMLookupObjects + * + * This routine looks up a virtual path in the library system and returns all + * matching elements. You provide a callback - one virtual path may match many + * objects in the library. XPLMLookupObjects returns the number of objects + * found. + * + * The latitude and longitude parameters specify the location the object will + * be used. The library system allows for scenery packages to only provide + * objects to certain local locations. Only objects that are allowed at the + * latitude/longitude you provide will be returned. + * + */ +XPLM_API int XPLMLookupObjects( + const char * inPath, + float inLatitude, + float inLongitude, + XPLMLibraryEnumerator_f enumerator, + void * ref); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMUtilities.h b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMUtilities.h new file mode 100644 index 0000000..bec319e --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/CHeaders/XPLM/XPLMUtilities.h @@ -0,0 +1,970 @@ +#ifndef _XPLMUtilities_h_ +#define _XPLMUtilities_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMUtilities + ***************************************************************************/ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FILE UTILITIES + ***************************************************************************/ +/* + * The XPLMUtilities file APIs provide some basic file and path functions for + * use with X-Plane. + * + * Directory Separators + * -------------------- + * + * The XPLM has two modes it can work in: + * + * * X-Plane native paths: all paths are UTF8 strings, using the unix forward + * slash (/) as the directory separating character. In native path mode, + * you use the same path format for all three operating systems. + * + * * Legacy OS paths: the directroy separator is \ for Windows, : for OS X, + * and / for Linux; OS paths are encoded in MacRoman for OS X using legacy + * HFS conventions, use the application code page for multi-byte encoding + * on Unix using DOS path conventions, and use UTF-8 for Linux. + * + * While legacy OS paths are the default, we strongly encourage you to opt in + * to native paths using the XPLMEnableFeature API. + * + * * All OS X plugins should enable native paths all of the time; if you do + * not do this, you will have to convert all paths back from HFS to Unix + * (and deal with MacRoman) - code written using native paths and the C + * file APIs "just works" on OS X. + * + * * For Linux plugins, there is no difference between the two encodings. + * + * * Windows plugins will need to convert the UTF8 file paths to UTF16 for + * use with the "wide" APIs. While it might seem tempting to stick with + * legacy OS paths (and just use the "ANSI" Windows APIs), X-Plane is fully + * unicode-capable, and will often be installed in paths where the user's + * directories have no ACP encoding. + * + * Full and Relative Paths + * ----------------------- + * + * Some of these APIs use full paths, but others use paths relative to the + * user's X-Plane installation. This is documented on a per-API basis. + * + */ + + +#if defined(XPLM200) +/* + * XPLMDataFileType + * + * These enums define types of data files you can load or unload using the + * SDK. + * + */ +enum { + /* A situation (.sit) file, which starts off a flight in a given * + * configuration. */ + xplm_DataFile_Situation = 1, + + /* A situation movie (.smo) file, which replays a past flight. */ + xplm_DataFile_ReplayMovie = 2, + + +}; +typedef int XPLMDataFileType; +#endif /* XPLM200 */ + +/* + * XPLMGetSystemPath + * + * This function returns the full path to the X-System folder. Note that this + * is a directory path, so it ends in a trailing : or /. + * + * The buffer you pass should be at least 512 characters long. The path is + * returned using the current native or OS path conventions. + * + */ +XPLM_API void XPLMGetSystemPath( + char * outSystemPath); + +/* + * XPLMGetPrefsPath + * + * This routine returns a full path to a file that is within X-Plane's + * preferences directory. (You should remove the file name back to the last + * directory separator to get the preferences directory using + * XPLMExtractFileAndPath.) + * + * The buffer you pass should be at least 512 characters long. The path is + * returned using the current native or OS path conventions. + * + */ +XPLM_API void XPLMGetPrefsPath( + char * outPrefsPath); + +/* + * XPLMGetDirectorySeparator + * + * This routine returns a string with one char and a null terminator that is + * the directory separator for the current platform. This allows you to write + * code that concatinates directory paths without having to #ifdef for + * platform. The character returned will reflect the current file path mode. + * + */ +XPLM_API const char * XPLMGetDirectorySeparator(void); + +/* + * XPLMExtractFileAndPath + * + * Given a full path to a file, this routine separates the path from the file. + * If the path is a partial directory (e.g. ends in : or \) the trailing + * directory separator is removed. This routine works in-place; a pointer to + * the file part of the buffer is returned; the original buffer still starts + * with the path and is null terminated with no trailing separator. + * + */ +XPLM_API char * XPLMExtractFileAndPath( + char * inFullPath); + +/* + * XPLMGetDirectoryContents + * + * This routine returns a list of files in a directory (specified by a full + * path, no trailing : or \). The output is returned as a list of NULL + * terminated strings. An index array (if specified) is filled with pointers + * into the strings. The last file is indicated by a zero-length string (and + * NULL in the indices). This routine will return 1 if you had capacity for + * all files or 0 if you did not. You can also skip a given number of files. + * + * * inDirectoryPath - a null terminated C string containing the full path to + * the directory with no trailing directory char. + * + * * inFirstReturn - the zero-based index of the first file in the directory + * to return. (Usually zero to fetch all in one pass.) + * + * * outFileNames - a buffer to receive a series of sequential null + * terminated C-string file names. A zero-length C string will be appended + * to the very end. + * + * * inFileNameBufSize - the size of the file name buffer in bytes. + * + * * outIndices - a pointer to an array of character pointers that will + * become an index into the directory. The last file will be followed by a + * NULL value. Pass NULL if you do not want indexing information. + * + * * inIndexCount - the max size of the index in entries. + * + * * outTotalFiles - if not NULL, this is filled in with the number of files + * in the directory. + * + * * outReturnedFiles - if not NULL, the number of files returned by this + * iteration. + * + * Return value: 1 if all info could be returned, 0 if there was a buffer + * overrun. + * + * WARNING: Before X-Plane 7 this routine did not properly iterate through + * directories. If X-Plane + * 6 compatibility is needed, use your own code to iterate directories. + * + */ +XPLM_API int XPLMGetDirectoryContents( + const char * inDirectoryPath, + int inFirstReturn, + char * outFileNames, + int inFileNameBufSize, + char ** outIndices, /* Can be NULL */ + int inIndexCount, + int * outTotalFiles, /* Can be NULL */ + int * outReturnedFiles); /* Can be NULL */ + +#if defined(XPLM200) +/* + * XPLMLoadDataFile + * + * Loads a data file of a given type. Paths must be relative to the X-System + * folder. To clear the replay, pass a NULL file name (this is only valid with + * replay movies, not sit files). + * + */ +XPLM_API int XPLMLoadDataFile( + XPLMDataFileType inFileType, + const char * inFilePath); /* Can be NULL */ +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMSaveDataFile + * + * Saves the current situation or replay; paths are relative to the X-System + * folder. + * + */ +XPLM_API int XPLMSaveDataFile( + XPLMDataFileType inFileType, + const char * inFilePath); +#endif /* XPLM200 */ + +/*************************************************************************** + * X-PLANE MISC + ***************************************************************************/ + +/* + * XPLMHostApplicationID + * + * While the plug-in SDK is only accessible to plugins running inside X-Plane, + * the original authors considered extending the API to other applications + * that shared basic infrastructure with X-Plane. These enumerations are + * hold-overs from that original roadmap; all values other than X-Plane are + * deprecated. Your plugin should never need this enumeration. + * + */ +enum { + xplm_Host_Unknown = 0, + + xplm_Host_XPlane = 1, + +#if defined(XPLM_DEPRECATED) + xplm_Host_PlaneMaker = 2, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_WorldMaker = 3, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_Briefer = 4, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_PartMaker = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_YoungsMod = 6, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_XAuto = 7, + +#endif /* XPLM_DEPRECATED */ + +}; +typedef int XPLMHostApplicationID; + +/* + * XPLMLanguageCode + * + * These enums define what language the sim is running in. These enumerations + * do not imply that the sim can or does run in all of these languages; they + * simply provide a known encoding in the event that a given sim version is + * localized to a certain language. + * + */ +enum { + xplm_Language_Unknown = 0, + + xplm_Language_English = 1, + + xplm_Language_French = 2, + + xplm_Language_German = 3, + + xplm_Language_Italian = 4, + + xplm_Language_Spanish = 5, + + xplm_Language_Korean = 6, + +#if defined(XPLM200) + xplm_Language_Russian = 7, + +#endif /* XPLM200 */ +#if defined(XPLM200) + xplm_Language_Greek = 8, + +#endif /* XPLM200 */ +#if defined(XPLM200) + xplm_Language_Japanese = 9, + +#endif /* XPLM200 */ +#if defined(XPLM300) + xplm_Language_Chinese = 10, + +#endif /* XPLM300 */ + +}; +typedef int XPLMLanguageCode; + +#if defined(XPLM200) +/* + * XPLMError_f + * + * An XPLM error callback is a function that you provide to receive debugging + * information from the plugin SDK. See XPLMSetErrorCallback for more + * information. NOTE: for the sake of debugging, your error callback will be + * called even if your plugin is not enabled, allowing you to receive debug + * info in your XPluginStart and XPluginStop callbacks. To avoid causing logic + * errors in the management code, do not call any other plugin routines from + * your error callback - it is only meant for catching errors in the + * debugging. + * + */ +typedef void (* XPLMError_f)( + const char * inMessage); +#endif /* XPLM200 */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMInitialized + * + * Deprecated: This function returns 1 if X-Plane has properly initialized the + * plug-in system. If this routine returns 0, many XPLM functions will not + * work. + * + * NOTE: because plugins are always called from within the XPLM, there is no + * need to check for initialization; it will always return 1. This routine is + * deprecated - you do not need to check it before continuing within your + * plugin. + * + */ +XPLM_API int XPLMInitialized(void); +#endif /* XPLM_DEPRECATED */ + +/* + * XPLMGetVersions + * + * This routine returns the revision of both X-Plane and the XPLM DLL. All + * versions are three-digit decimal numbers (e.g. 606 for version 6.06 of + * X-Plane); the current revision of the XPLM is 200 (2.00). This routine also + * returns the host ID of the app running us. + * + * The most common use of this routine is to special-case around X-Plane + * version-specific behavior. + * + */ +XPLM_API void XPLMGetVersions( + int * outXPlaneVersion, + int * outXPLMVersion, + XPLMHostApplicationID * outHostID); + +/* + * XPLMGetLanguage + * + * This routine returns the langauge the sim is running in. + * + */ +XPLM_API XPLMLanguageCode XPLMGetLanguage(void); + +#if defined(XPLM200) +/* + * XPLMFindSymbol + * + * This routine will attempt to find the symbol passed in the inString + * parameter. If the symbol is found a pointer the function is returned, + * othewise the function will return NULL. + * + * You can use XPLMFindSymbol to utilize newer SDK API features without + * requiring newer versions of the SDK (and X-Plane) as your minimum X-Plane + * version as follows: + * + * * Define the XPLMnnn macro to the minimum required XPLM version you will + * ship with (e.g. XPLM210 for X-Plane 10 compatibility). + * + * * Use XPLMGetVersions and XPLMFindSymbol to detect that the host sim is + * new enough to use new functions and resolve function pointers. + * + * * Conditionally use the new functions if and only if XPLMFindSymbol only + * returns a non- NULL pointer. + * + * Warning: you should always check the XPLM API version as well as the + * results of XPLMFindSymbol to determine if funtionality is safe to use. + * + * To use functionality via XPLMFindSymbol you will need to copy your own + * definitions of the X-Plane API prototypes and cast the returned pointer to + * the correct type. + * + */ +XPLM_API void * XPLMFindSymbol( + const char * inString); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMSetErrorCallback + * + * XPLMSetErrorCallback installs an error-reporting callback for your plugin. + * Normally the plugin system performs minimum diagnostics to maximize + * performance. When you install an error callback, you will receive calls due + * to certain plugin errors, such as passing bad parameters or incorrect data. + * + * Important: the error callback determines *programming* errors, e.g. bad API + * parameters. Every error that is returned by the error callback represents a + * mistake in your plugin that you should fix. Error callbacks are not used to + * report expected run-time problems (e.g. disk I/O errors). + * + * The intention is for you to install the error callback during debug + * sections and put a break-point inside your callback. This will cause you to + * break into the debugger from within the SDK at the point in your plugin + * where you made an illegal call. + * + * Installing an error callback may activate error checking code that would + * not normally run, and this may adversely affect performance, so do not + * leave error callbacks installed in shipping plugins. Since the only useful + * response to an error is to change code, error callbacks are not useful "in + * the field". + * + */ +XPLM_API void XPLMSetErrorCallback( + XPLMError_f inCallback); +#endif /* XPLM200 */ + +/* + * XPLMDebugString + * + * This routine outputs a C-style string to the Log.txt file. The file is + * immediately flushed so you will not lose data. (This does cause a + * performance penalty.) + * + * Please do *not* leave routine diagnostic logging enabled in your shipping + * plugin. The X-Plane Log file is shared by X-Plane and every plugin in the + * system, and plugins that (when functioning normally) print verbose log + * output make it difficult for developers to find error conditions from other + * parts of the system. + * + */ +XPLM_API void XPLMDebugString( + const char * inString); + +/* + * XPLMSpeakString + * + * This function displays the string in a translucent overlay over the current + * display and also speaks the string if text-to-speech is enabled. The string + * is spoken asynchronously, this function returns immediately. This function + * may not speak or print depending on user preferences. + * + */ +XPLM_API void XPLMSpeakString( + const char * inString); + +/* + * XPLMGetVirtualKeyDescription + * + * Given a virtual key code (as defined in XPLMDefs.h) this routine returns a + * human-readable string describing the character. This routine is provided + * for showing users what keyboard mappings they have set up. The string may + * read 'unknown' or be a blank or NULL string if the virtual key is unknown. + * + */ +XPLM_API const char * XPLMGetVirtualKeyDescription( + char inVirtualKey); + +/* + * XPLMReloadScenery + * + * XPLMReloadScenery reloads the current set of scenery. You can use this + * function in two typical ways: simply call it to reload the scenery, picking + * up any new installed scenery, .env files, etc. from disk. Or, change the + * lat/ref and lon/ref data refs and then call this function to shift the + * scenery environment. This routine is equivalent to picking "reload + * scenery" from the developer menu. + * + */ +XPLM_API void XPLMReloadScenery(void); + +#if defined(XPLM200) +/*************************************************************************** + * X-PLANE COMMAND MANAGEMENT + ***************************************************************************/ +/* + * The command management APIs let plugins interact with the command-system in + * X-Plane, the abstraction behind keyboard presses and joystick buttons. This + * API lets you create new commands and modify the behavior (or get + * notification) of existing ones. + * + * X-Plane Command Phases + * ---------------------- + * + * X-Plane commands are not instantaneous; they operate over a duration. + * (Think of a joystick button press - you can press, hold down, and then + * release the joystick button; X-Plane commands model this entire process.) + * + * An X-Plane command consists of three phases: a beginning, continuous + * repetition, and an ending. The command may be repeated zero times in its + * duration, followed by one command ending. Command begin and end messges are + * balanced, but a command may be bound to more than one event source (e.g. a + * keyboard key and a joystick button), in which case you may receive a second + * begin during before any end). + * + * When you issue commands in the plugin system, you *must* balance every call + * to XPLMCommandBegin with a call to XPLMCommandEnd with the same command + * reference. + * + * Command Behavior Modification + * ----------------------------- + * + * You can register a callback to handle a command either before or after + * X-Plane does; if you receive the command before X-Plane you have the option + * to either let X-Plane handle the command or hide the command from X-Plane. + * This lets plugins both augment commands and replace them. + * + * If you register for an existing command, be sure that you are *consistent* + * in letting X-Plane handle or not handle the command; you are responsible + * for passing a *balanced* number of begin and end messages to X-Plane. (E.g. + * it is not legal to pass all the begin messages to X-Plane but hide all the + * end messages). + * + */ + + +/* + * XPLMCommandPhase + * + * The phases of a command. + * + */ +enum { + /* The command is being started. */ + xplm_CommandBegin = 0, + + /* The command is continuing to execute. */ + xplm_CommandContinue = 1, + + /* The command has ended. */ + xplm_CommandEnd = 2, + + +}; +typedef int XPLMCommandPhase; + +/* + * XPLMCommandRef + * + * A command ref is an opaque identifier for an X-Plane command. Command + * references stay the same for the life of your plugin but not between + * executions of X-Plane. Command refs are used to execute commands, create + * commands, and create callbacks for particular commands. + * + * Note that a command is not "owned" by a particular plugin. Since many + * plugins may participate in a command's execution, the command does not go + * away if the plugin that created it is unloaded. + * + */ +typedef void * XPLMCommandRef; + +/* + * XPLMCommandCallback_f + * + * A command callback is a function in your plugin that is called when a + * command is pressed. Your callback receives the command reference for the + * particular command, the phase of the command that is executing, and a + * reference pointer that you specify when registering the callback. + * + * Your command handler should return 1 to let processing of the command + * continue to other plugins and X-Plane, or 0 to halt processing, potentially + * bypassing X-Plane code. + * + */ +typedef int (* XPLMCommandCallback_f)( + XPLMCommandRef inCommand, + XPLMCommandPhase inPhase, + void * inRefcon); + +/* + * XPLMFindCommand + * + * XPLMFindCommand looks up a command by name, and returns its command + * reference or NULL if the command does not exist. + * + */ +XPLM_API XPLMCommandRef XPLMFindCommand( + const char * inName); + +/* + * XPLMCommandBegin + * + * XPLMCommandBegin starts the execution of a command, specified by its + * command reference. The command is "held down" until XPLMCommandEnd is + * called. You must balance each XPLMCommandBegin call with an XPLMCommandEnd + * call. + * + */ +XPLM_API void XPLMCommandBegin( + XPLMCommandRef inCommand); + +/* + * XPLMCommandEnd + * + * XPLMCommandEnd ends the execution of a given command that was started with + * XPLMCommandBegin. You must not issue XPLMCommandEnd for a command you did + * not begin. + * + */ +XPLM_API void XPLMCommandEnd( + XPLMCommandRef inCommand); + +/* + * XPLMCommandOnce + * + * This executes a given command momentarily, that is, the command begins and + * ends immediately. This is the equivalent of calling XPLMCommandBegin() and + * XPLMCommandEnd() back ot back. + * + */ +XPLM_API void XPLMCommandOnce( + XPLMCommandRef inCommand); + +/* + * XPLMCreateCommand + * + * XPLMCreateCommand creates a new command for a given string. If the command + * already exists, the existing command reference is returned. The description + * may appear in user interface contexts, such as the joystick configuration + * screen. + * + */ +XPLM_API XPLMCommandRef XPLMCreateCommand( + const char * inName, + const char * inDescription); + +/* + * XPLMRegisterCommandHandler + * + * XPLMRegisterCommandHandler registers a callback to be called when a command + * is executed. You provide a callback with a reference pointer. + * + * If inBefore is true, your command handler callback will be executed before + * X-Plane executes the command, and returning 0 from your callback will + * disable X-Plane's processing of the command. If inBefore is false, your + * callback will run after X-Plane. (You can register a single callback both + * before and after a command.) + * + */ +XPLM_API void XPLMRegisterCommandHandler( + XPLMCommandRef inComand, + XPLMCommandCallback_f inHandler, + int inBefore, + void * inRefcon); + +/* + * XPLMUnregisterCommandHandler + * + * XPLMUnregisterCommandHandler removes a command callback registered with + * XPLMRegisterCommandHandler. + * + */ +XPLM_API void XPLMUnregisterCommandHandler( + XPLMCommandRef inComand, + XPLMCommandCallback_f inHandler, + int inBefore, + void * inRefcon); + +#endif /* XPLM200 */ +#if defined(XPLM_DEPRECATED) +/*************************************************************************** + * X-PLANE USER INTERACTION + ***************************************************************************/ +/* + * WARNING: The legacy user interaction API is deprecated; while it was the + * only way to run commands in X-Plane 6,7 and 8, it is obsolete, and was + * replaced by the command system API in X-Plane 9. You should not use this + * API; replace any of the calls below with XPLMCommand invocations based on + * persistent command strings. The documentation that follows is for historic + * reference only. + * + * The legacy user interaction APIs let you simulate commands the user can do + * with a joystick, keyboard etc. Note that it is generally safer for future + * compatibility to use one of these commands than to manipulate the + * underlying sim data. + * + */ + + +/* + * XPLMCommandKeyID + * + * These enums represent all the keystrokes available within X-Plane. They can + * be sent to X-Plane directly. For example, you can reverse thrust using + * these enumerations. + * + */ +enum { + xplm_key_pause=0, + xplm_key_revthrust, + xplm_key_jettison, + xplm_key_brakesreg, + xplm_key_brakesmax, + xplm_key_gear, + xplm_key_timedn, + xplm_key_timeup, + xplm_key_fadec, + xplm_key_otto_dis, + xplm_key_otto_atr, + xplm_key_otto_asi, + xplm_key_otto_hdg, + xplm_key_otto_gps, + xplm_key_otto_lev, + xplm_key_otto_hnav, + xplm_key_otto_alt, + xplm_key_otto_vvi, + xplm_key_otto_vnav, + xplm_key_otto_nav1, + xplm_key_otto_nav2, + xplm_key_targ_dn, + xplm_key_targ_up, + xplm_key_hdgdn, + xplm_key_hdgup, + xplm_key_barodn, + xplm_key_baroup, + xplm_key_obs1dn, + xplm_key_obs1up, + xplm_key_obs2dn, + xplm_key_obs2up, + xplm_key_com1_1, + xplm_key_com1_2, + xplm_key_com1_3, + xplm_key_com1_4, + xplm_key_nav1_1, + xplm_key_nav1_2, + xplm_key_nav1_3, + xplm_key_nav1_4, + xplm_key_com2_1, + xplm_key_com2_2, + xplm_key_com2_3, + xplm_key_com2_4, + xplm_key_nav2_1, + xplm_key_nav2_2, + xplm_key_nav2_3, + xplm_key_nav2_4, + xplm_key_adf_1, + xplm_key_adf_2, + xplm_key_adf_3, + xplm_key_adf_4, + xplm_key_adf_5, + xplm_key_adf_6, + xplm_key_transpon_1, + xplm_key_transpon_2, + xplm_key_transpon_3, + xplm_key_transpon_4, + xplm_key_transpon_5, + xplm_key_transpon_6, + xplm_key_transpon_7, + xplm_key_transpon_8, + xplm_key_flapsup, + xplm_key_flapsdn, + xplm_key_cheatoff, + xplm_key_cheaton, + xplm_key_sbrkoff, + xplm_key_sbrkon, + xplm_key_ailtrimL, + xplm_key_ailtrimR, + xplm_key_rudtrimL, + xplm_key_rudtrimR, + xplm_key_elvtrimD, + xplm_key_elvtrimU, + xplm_key_forward, + xplm_key_down, + xplm_key_left, + xplm_key_right, + xplm_key_back, + xplm_key_tower, + xplm_key_runway, + xplm_key_chase, + xplm_key_free1, + xplm_key_free2, + xplm_key_spot, + xplm_key_fullscrn1, + xplm_key_fullscrn2, + xplm_key_tanspan, + xplm_key_smoke, + xplm_key_map, + xplm_key_zoomin, + xplm_key_zoomout, + xplm_key_cycledump, + xplm_key_replay, + xplm_key_tranID, + xplm_key_max +}; +typedef int XPLMCommandKeyID; + +/* + * XPLMCommandButtonID + * + * These are enumerations for all of the things you can do with a joystick + * button in X-Plane. They currently match the buttons menu in the equipment + * setup dialog, but these enums will be stable even if they change in + * X-Plane. + * + */ +enum { + xplm_joy_nothing=0, + xplm_joy_start_all, + xplm_joy_start_0, + xplm_joy_start_1, + xplm_joy_start_2, + xplm_joy_start_3, + xplm_joy_start_4, + xplm_joy_start_5, + xplm_joy_start_6, + xplm_joy_start_7, + xplm_joy_throt_up, + xplm_joy_throt_dn, + xplm_joy_prop_up, + xplm_joy_prop_dn, + xplm_joy_mixt_up, + xplm_joy_mixt_dn, + xplm_joy_carb_tog, + xplm_joy_carb_on, + xplm_joy_carb_off, + xplm_joy_trev, + xplm_joy_trm_up, + xplm_joy_trm_dn, + xplm_joy_rot_trm_up, + xplm_joy_rot_trm_dn, + xplm_joy_rud_lft, + xplm_joy_rud_cntr, + xplm_joy_rud_rgt, + xplm_joy_ail_lft, + xplm_joy_ail_cntr, + xplm_joy_ail_rgt, + xplm_joy_B_rud_lft, + xplm_joy_B_rud_rgt, + xplm_joy_look_up, + xplm_joy_look_dn, + xplm_joy_look_lft, + xplm_joy_look_rgt, + xplm_joy_glance_l, + xplm_joy_glance_r, + xplm_joy_v_fnh, + xplm_joy_v_fwh, + xplm_joy_v_tra, + xplm_joy_v_twr, + xplm_joy_v_run, + xplm_joy_v_cha, + xplm_joy_v_fr1, + xplm_joy_v_fr2, + xplm_joy_v_spo, + xplm_joy_flapsup, + xplm_joy_flapsdn, + xplm_joy_vctswpfwd, + xplm_joy_vctswpaft, + xplm_joy_gear_tog, + xplm_joy_gear_up, + xplm_joy_gear_down, + xplm_joy_lft_brake, + xplm_joy_rgt_brake, + xplm_joy_brakesREG, + xplm_joy_brakesMAX, + xplm_joy_speedbrake, + xplm_joy_ott_dis, + xplm_joy_ott_atr, + xplm_joy_ott_asi, + xplm_joy_ott_hdg, + xplm_joy_ott_alt, + xplm_joy_ott_vvi, + xplm_joy_tim_start, + xplm_joy_tim_reset, + xplm_joy_ecam_up, + xplm_joy_ecam_dn, + xplm_joy_fadec, + xplm_joy_yaw_damp, + xplm_joy_art_stab, + xplm_joy_chute, + xplm_joy_JATO, + xplm_joy_arrest, + xplm_joy_jettison, + xplm_joy_fuel_dump, + xplm_joy_puffsmoke, + xplm_joy_prerotate, + xplm_joy_UL_prerot, + xplm_joy_UL_collec, + xplm_joy_TOGA, + xplm_joy_shutdown, + xplm_joy_con_atc, + xplm_joy_fail_now, + xplm_joy_pause, + xplm_joy_rock_up, + xplm_joy_rock_dn, + xplm_joy_rock_lft, + xplm_joy_rock_rgt, + xplm_joy_rock_for, + xplm_joy_rock_aft, + xplm_joy_idle_hilo, + xplm_joy_lanlights, + xplm_joy_max +}; +typedef int XPLMCommandButtonID; + +/* + * XPLMSimulateKeyPress + * + * This function simulates a key being pressed for X-Plane. The keystroke goes + * directly to X-Plane; it is never sent to any plug-ins. However, since this + * is a raw key stroke it may be mapped by the keys file or enter text into a + * field. + * + * Deprecated: use XPLMCommandOnce + * + */ +XPLM_API void XPLMSimulateKeyPress( + int inKeyType, + int inKey); + +/* + * XPLMCommandKeyStroke + * + * This routine simulates a command-key stroke. However, the keys are done by + * function, not by actual letter, so this function works even if the user has + * remapped their keyboard. Examples of things you might do with this include + * pausing the simulator. + * + * Deprecated: use XPLMCommandOnce + * + */ +XPLM_API void XPLMCommandKeyStroke( + XPLMCommandKeyID inKey); + +/* + * XPLMCommandButtonPress + * + * This function simulates any of the actions that might be taken by pressing + * a joystick button. However, this lets you call the command directly rather + * than have to know which button is mapped where. Important: you must release + * each button you press. The APIs are separate so that you can 'hold down' a + * button for a fixed amount of time. + * + * Deprecated: use XPLMCommandBegin. + * + */ +XPLM_API void XPLMCommandButtonPress( + XPLMCommandButtonID inButton); + +/* + * XPLMCommandButtonRelease + * + * This function simulates any of the actions that might be taken by pressing + * a joystick button. See XPLMCommandButtonPress. + * + * Deprecated: use XPLMCommandEnd. + * + */ +XPLM_API void XPLMCommandButtonRelease( + XPLMCommandButtonID inButton); + +#endif /* XPLM_DEPRECATED */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPStandardWidgets.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPStandardWidgets.pas new file mode 100644 index 0000000..d77f383 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPStandardWidgets.pas @@ -0,0 +1,470 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPStandardWidgets; +INTERFACE +{ + ## THEORY OF OPERATION + + The standard widgets are widgets built into the widgets library. While you + can gain access to the widget function that drives them, you generally use + them by calling XPCreateWidget and then listening for special messages, + etc. + + The standard widgets often send mesages to themselves when the user + performs an event; these messages are sent up the widget hierarchy until + they are handled. So you can add a widget proc directly to a push button + (for example) to intercept the message when it is clicked, or you can put + one widget proc on a window for all of the push buttons in the window. Most + of these messages contain the original widget ID as a parameter so you can + know which widget is messaging no matter who it is sent to. +} + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * MAIN WINDOW + ___________________________________________________________________________} +{ + The main window widget class provides a "window" as the user knows it. + These windows are dragable and can be selected. Use them to create floating + windows and non-modal dialogs. +} + + +CONST + xpWidgetClass_MainWindow = 1; + + { + Main Window Type Values + + These type values are used to control the appearance of a main window. + } + { The standard main window; pin stripes on XP7, metal frame on XP 6. } + xpMainWindowStyle_MainWindow = 0 +; + { A translucent dark gray window, like the one ATC messages appear in. } + xpMainWindowStyle_Translucent = 1 +; + + { + Main Window Properties + } + { This property specifies the type of window. Set to one of the main window } + { types above. } + xpProperty_MainWindowType = 1100 +; + { This property specifies whether the main window has close boxes in its } + { corners. } + xpProperty_MainWindowHasCloseBoxes = 1200 +; + + { + MainWindow Messages + } + { This message is sent when the close buttons are pressed for your window. } + xpMessage_CloseButtonPushed = 1200 +; + +{___________________________________________________________________________ + * SUB WINDOW + ___________________________________________________________________________} +{ + X-Plane dialogs are divided into separate areas; the sub window widgets + allow you to make these areas. Create one main window and place several + subwindows inside it. Then place your controls inside the subwindows. +} + + +CONST + xpWidgetClass_SubWindow = 2; + + { + SubWindow Type Values + + These values control the appearance of the subwindow. + } + { A panel that sits inside a main window. } + xpSubWindowStyle_SubWindow = 0 +; + { A screen that sits inside a panel for showing text information. } + xpSubWindowStyle_Screen = 2 +; + { A list view for scrolling lists. } + xpSubWindowStyle_ListView = 3 +; + + { + SubWindow Properties + } + { This property specifies the type of window. Set to one of the subwindow } + { types above. } + xpProperty_SubWindowType = 1200 +; + +{___________________________________________________________________________ + * BUTTON + ___________________________________________________________________________} +{ + The button class provides a number of different button styles and + behaviors, including push buttons, radio buttons, check boxes, etc. The + button label appears on or next to the button depending on the button's + appearance, or type. + + The button's behavior is a separate property that dictates who it hilights + and what kinds of messages it sends. Since behavior and type are different, + you can do strange things like make check boxes that act as push buttons or + push buttons with radio button behavior. + + In X-Plane 6 there were no check box graphics. The result is the following + behavior: in X-Plane + 6 all check box and radio buttons are round (radio-button style) buttons; + in X-Plane 7 they are all square (check-box style) buttons. In a future + version of X-Plane, the xpButtonBehavior enums will provide the correct + graphic (check box or radio button) giving the expected result. +} + + +CONST + xpWidgetClass_Button = 3; + + { + Button Types + + These define the visual appearance of buttons but not how they respond to + the mouse. + } + { This is a standard push button, like an 'OK' or 'Cancel' button in a dialog} + { box. } + xpPushButton = 0 +; + { A check box or radio button. Use this and the button behaviors below to } + { get the desired behavior. } + xpRadioButton = 1 +; + { A window close box. } + xpWindowCloseBox = 3 +; + { A small down arrow. } + xpLittleDownArrow = 5 +; + { A small up arrow. } + xpLittleUpArrow = 6 +; + + { + Button Behavior Values + + These define how the button responds to mouse clicks. + } + { Standard push button behavior. The button hilites while the mouse is } + { clicked over it and unhilites when the mouse is moved outside of it or } + { released. If the mouse is released over the button, the } + { xpMsg_PushButtonPressed message is sent. } + xpButtonBehaviorPushButton = 0 +; + { Check box behavior. The button immediately toggles its value when the mouse} + { is clicked and sends out a xpMsg_ButtonStateChanged message. } + xpButtonBehaviorCheckBox = 1 +; + { Radio button behavior. The button immediately sets its state to one and } + { sends out a xpMsg_ButtonStateChanged message if it was not already set to } + { one. You must turn off other radio buttons in a group in your code. } + xpButtonBehaviorRadioButton = 2 +; + + { + Button Properties + } + { This property sets the visual type of button. Use one of the button types } + { above. } + xpProperty_ButtonType = 1300 +; + { This property sets the button's behavior. Use one of the button behaviors } + { above. } + xpProperty_ButtonBehavior = 1301 +; + { This property tells whether a check box or radio button is "checked" or } + { not. Not used for push buttons. } + xpProperty_ButtonState = 1302 +; + + { + Button Messages + + These messages are sent by the button to itself and then up the widget + chain when the button is clicked. (You may intercept them by providing a + widget handler for the button itself or by providing a handler in a parent + widget.) + } + { This message is sent when the user completes a click and release in a } + { button with push button behavior. Parameter one of the message is the } + { widget ID of the button. This message is dispatched up the widget } + { hierarchy. } + xpMsg_PushButtonPressed = 1300 +; + { This message is sent when a button is clicked that has radio button or } + { check box behavior and its value changes. (Note that if the value changes } + { by setting a property you do not receive this message!) Parameter one is } + { the widget ID of the button, parameter 2 is the new state value, either } + { zero or one. This message is dispatched up the widget hierarchy. } + xpMsg_ButtonStateChanged = 1301 +; + +{___________________________________________________________________________ + * TEXT FIELD + ___________________________________________________________________________} +{ + The text field widget provides an editable text field including mouse + selection and keyboard navigation. The contents of the text field are its + descriptor. (The descriptor changes as the user types.) + + The text field can have a number of types, that effect the visual layout of + the text field. The text field sends messages to itself so you may control + its behavior. + + If you need to filter keystrokes, add a new handler and intercept the key + press message. Since key presses are passed by pointer, you can modify the + keystroke and pass it through to the text field widget. + + WARNING: in X-Plane before 7.10 (including 6.70) null characters could + crash X-Plane. To prevent this, wrap this object with a filter function + (more instructions can be found on the SDK website). +} + + +CONST + xpWidgetClass_TextField = 4; + + { + Text Field Type Values + + These control the look of the text field. + } + { A field for text entry. } + xpTextEntryField = 0 +; + { A transparent text field. The user can type and the text is drawn, but no } + { background is drawn. You can draw your own background by adding a widget } + { handler and prehandling the draw message. } + xpTextTransparent = 3 +; + { A translucent edit field, dark gray. } + xpTextTranslucent = 4 +; + + { + Text Field Properties + } + { This is the character position the selection starts at, zero based. If it } + { is the same as the end insertion point, the insertion point is not a } + { selection. } + xpProperty_EditFieldSelStart = 1400 +; + { This is the character position of the end of the selection. } + xpProperty_EditFieldSelEnd = 1401 +; + { This is the character position a drag was started at if the user is } + { dragging to select text, or -1 if a drag is not in progress. } + xpProperty_EditFieldSelDragStart = 1402 +; + { This is the type of text field to display, from the above list. } + xpProperty_TextFieldType = 1403 +; + { Set this property to 1 to password protect the field. Characters will be } + { drawn as *s even though the descriptor will contain plain-text. } + xpProperty_PasswordMode = 1404 +; + { The max number of characters you can enter, if limited. Zero means } + { unlimited. } + xpProperty_MaxCharacters = 1405 +; + { The first visible character on the left. This effectively scrolls the text} + { field. } + xpProperty_ScrollPosition = 1406 +; + { The font to draw the field's text with. (An XPLMFontID.) } + xpProperty_Font = 1407 +; + { This is the active side of the insert selection. (Internal) } + xpProperty_ActiveEditSide = 1408 +; + + { + Text Field Messages + } + { The text field sends this message to itself when its text changes. It sends} + { the message up the call chain; param1 is the text field's widget ID. } + xpMsg_TextFieldChanged = 1400 +; + +{___________________________________________________________________________ + * SCROLL BAR + ___________________________________________________________________________} +{ + A standard scroll bar or slider control. The scroll bar has a minimum, + maximum and current value that is updated when the user drags it. The + scroll bar sends continuous messages as it is dragged. +} + + +CONST + xpWidgetClass_ScrollBar = 5; + + { + Scroll Bar Type Values + + This defines how the scroll bar looks. + } + { A standard X-Plane scroll bar (with arrows on the ends). } + xpScrollBarTypeScrollBar = 0 +; + { A slider, no arrows. } + xpScrollBarTypeSlider = 1 +; + + { + Scroll Bar Properties + } + { The current position of the thumb (in between the min and max, inclusive) } + xpProperty_ScrollBarSliderPosition = 1500 +; + { The value the scroll bar has when the thumb is in the lowest position. } + xpProperty_ScrollBarMin = 1501 +; + { The value the scroll bar has when the thumb is in the highest position. } + xpProperty_ScrollBarMax = 1502 +; + { How many units to move the scroll bar when clicking next to the thumb. The } + { scroll bar always moves one unit when the arrows are clicked. } + xpProperty_ScrollBarPageAmount = 1503 +; + { The type of scrollbar from the enums above. } + xpProperty_ScrollBarType = 1504 +; + { Used internally. } + xpProperty_ScrollBarSlop = 1505 +; + + { + Scroll Bar Messages + } + { The scroll bar sends this message when the slider position changes. It } + { sends the message up the call chain; param1 is the Scroll Bar widget ID. } + xpMsg_ScrollBarSliderPositionChanged = 1500 +; + +{___________________________________________________________________________ + * CAPTION + ___________________________________________________________________________} +{ + A caption is a simple widget that shows its descriptor as a string, useful + for labeling parts of a window. It always shows its descriptor as its + string and is otherwise transparent. +} + + +CONST + xpWidgetClass_Caption = 6; + + { + Caption Properties + } + { This property specifies whether the caption is lit; use lit captions } + { against screens. } + xpProperty_CaptionLit = 1600 +; + +{___________________________________________________________________________ + * GENERAL GRAPHICS + ___________________________________________________________________________} +{ + The general graphics widget can show one of many icons available from + X-Plane. +} + + +CONST + xpWidgetClass_GeneralGraphics = 7; + + { + General Graphics Types Values + + These define the icon for the general graphics. + } + xpShip = 4 +; + xpILSGlideScope = 5 +; + xpMarkerLeft = 6 +; + xp_Airport = 7 +; + xpNDB = 8 +; + xpVOR = 9 +; + xpRadioTower = 10 +; + xpAircraftCarrier = 11 +; + xpFire = 12 +; + xpMarkerRight = 13 +; + xpCustomObject = 14 +; + xpCoolingTower = 15 +; + xpSmokeStack = 16 +; + xpBuilding = 17 +; + xpPowerLine = 18 +; + xpVORWithCompassRose = 19 +; + xpOilPlatform = 21 +; + xpOilPlatformSmall = 22 +; + xpWayPoint = 23 +; + + { + General Graphics Properties + } + { This property controls the type of icon that is drawn. } + xpProperty_GeneralGraphicsType = 1700 +; + +{___________________________________________________________________________ + * PROGRESS INDICATOR + ___________________________________________________________________________} +{ + This widget implements a progress indicator as seen when X-Plane starts up. +} + +CONST + xpWidgetClass_Progress = 8; + + { + Progress Indicator Properties + } + { This is the current value of the progress indicator. } + xpProperty_ProgressPosition = 1800 +; + { This is the minimum value, equivalent to 0% filled. } + xpProperty_ProgressMin = 1801 +; + { This is the maximum value, equivalent to 100% filled. } + xpProperty_ProgressMax = 1802 +; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPUIGraphics.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPUIGraphics.pas new file mode 100644 index 0000000..65e0636 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPUIGraphics.pas @@ -0,0 +1,342 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPUIGraphics; +INTERFACE + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * UI GRAPHICS + ___________________________________________________________________________} + + { + XPWindowStyle + + There are a few built-in window styles in X-Plane that you can use. + + Note that X-Plane 6 does not offer real shadow-compositing; you must make + sure to put a window on top of another window of the right style to the + shadows work, etc. This applies to elements with insets and shadows. The + rules are: + + Sub windows must go on top of main windows, and screens and list views on + top of subwindows. Only help and main windows can be over the main screen. + + With X-Plane 7 any window or element may be placed over any other element. + + Some windows are scaled by stretching, some by repeating. The drawing + routines know which scaling method to use. The list view cannot be rescaled + in X-Plane 6 because it has both a repeating pattern and a gradient in one + element. All other elements can be rescaled. + } +TYPE + XPWindowStyle = ( + { An LCD screen that shows help. } + xpWindow_Help = 0 + + { A dialog box window. } + ,xpWindow_MainWindow = 1 + + { A panel or frame within a dialog box window. } + ,xpWindow_SubWindow = 2 + + { An LCD screen within a panel to hold text displays. } + ,xpWindow_Screen = 4 + + { A list view within a panel for scrolling file names, etc. } + ,xpWindow_ListView = 5 + + ); + PXPWindowStyle = ^XPWindowStyle; + + { + XPDrawWindow + + This routine draws a window of the given dimensions at the given offset on + the virtual screen in a given style. The window is automatically scaled as + appropriate using a bitmap scaling technique (scaling or repeating) as + appropriate to the style. + } + PROCEDURE XPDrawWindow( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inStyle : XPWindowStyle); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWindowDefaultDimensions + + This routine returns the default dimensions for a window. Output is either + a minimum or fixed value depending on whether the window is scalable. + } + PROCEDURE XPGetWindowDefaultDimensions( + inStyle : XPWindowStyle; + outWidth : PInteger; { Can be nil } + outHeight : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPElementStyle + + Elements are individually drawable UI things like push buttons, etc. The + style defines what kind of element you are drawing. Elements can be + stretched in one or two dimensions (depending on the element). Some + elements can be lit. + + In X-Plane 6 some elements must be drawn over metal. Some are scalable and + some are not. Any element can be drawn anywhere in X-Plane 7. + + Scalable Axis Required Background + } +TYPE + XPElementStyle = ( + { x metal } + xpElement_TextField = 6 + + { none metal } + ,xpElement_CheckBox = 9 + + { none metal } + ,xpElement_CheckBoxLit = 10 + + { none window header } + ,xpElement_WindowCloseBox = 14 + + { none window header } + ,xpElement_WindowCloseBoxPressed = 15 + + { x metal } + ,xpElement_PushButton = 16 + + { x metal } + ,xpElement_PushButtonLit = 17 + + { none any } + ,xpElement_OilPlatform = 24 + + { none any } + ,xpElement_OilPlatformSmall = 25 + + { none any } + ,xpElement_Ship = 26 + + { none any } + ,xpElement_ILSGlideScope = 27 + + { none any } + ,xpElement_MarkerLeft = 28 + + { none any } + ,xpElement_Airport = 29 + + { none any } + ,xpElement_Waypoint = 30 + + { none any } + ,xpElement_NDB = 31 + + { none any } + ,xpElement_VOR = 32 + + { none any } + ,xpElement_RadioTower = 33 + + { none any } + ,xpElement_AircraftCarrier = 34 + + { none any } + ,xpElement_Fire = 35 + + { none any } + ,xpElement_MarkerRight = 36 + + { none any } + ,xpElement_CustomObject = 37 + + { none any } + ,xpElement_CoolingTower = 38 + + { none any } + ,xpElement_SmokeStack = 39 + + { none any } + ,xpElement_Building = 40 + + { none any } + ,xpElement_PowerLine = 41 + + { none metal } + ,xpElement_CopyButtons = 45 + + { none metal } + ,xpElement_CopyButtonsWithEditingGrid = 46 + + { x, y metal } + ,xpElement_EditingGrid = 47 + + { THIS CAN PROBABLY BE REMOVED } + ,xpElement_ScrollBar = 48 + + { none any } + ,xpElement_VORWithCompassRose = 49 + + { none metal } + ,xpElement_Zoomer = 51 + + { x, y metal } + ,xpElement_TextFieldMiddle = 52 + + { none metal } + ,xpElement_LittleDownArrow = 53 + + { none metal } + ,xpElement_LittleUpArrow = 54 + + { none metal } + ,xpElement_WindowDragBar = 61 + + { none metal } + ,xpElement_WindowDragBarSmooth = 62 + + ); + PXPElementStyle = ^XPElementStyle; + + { + XPDrawElement + + XPDrawElement draws a given element at an offset on the virtual screen in + set dimensions. + *Even* if the element is not scalable, it will be scaled if the width and + height do not match the preferred dimensions; it'll just look ugly. Pass + inLit to see the lit version of the element; if the element cannot be lit + this is ignored. + } + PROCEDURE XPDrawElement( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inStyle : XPElementStyle; + inLit : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetElementDefaultDimensions + + This routine returns the recommended or minimum dimensions of a given UI + element. outCanBeLit tells whether the element has both a lit and unlit + state. Pass `NULL` to not receive any of these parameters. + } + PROCEDURE XPGetElementDefaultDimensions( + inStyle : XPElementStyle; + outWidth : PInteger; { Can be nil } + outHeight : PInteger; { Can be nil } + outCanBeLit : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPTrackStyle + + A track is a UI element that displays a value vertically or horizontally. + X-Plane has three kinds of tracks: scroll bars, sliders, and progress bars. + Tracks can be displayed either horizontally or vertically; tracks will + choose their own layout based on the larger dimension of their dimensions + (e.g. they know if they are tall or wide). Sliders may be lit or unlit + (showing the user manipulating them). + + - ScrollBar: this is a standard scroll bar with arrows and a thumb to drag. + - Slider: this is a simple track with a ball in the middle that can be + slid. + - Progress: this is a progress indicator showing how a long task is going. + } +TYPE + XPTrackStyle = ( + { not over metal can be lit can be rotated } + xpTrack_ScrollBar = 0 + + { over metal can be lit can be rotated } + ,xpTrack_Slider = 1 + + { over metal cannot be lit cannot be rotated } + ,xpTrack_Progress = 2 + + ); + PXPTrackStyle = ^XPTrackStyle; + + { + XPDrawTrack + + This routine draws a track. You pass in the track dimensions and size; the + track picks the optimal orientation for these dimensions. Pass in the + track's minimum current and maximum values; the indicator will be + positioned appropriately. You can also specify whether the track is lit or + not. + } + PROCEDURE XPDrawTrack( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inMin : Integer; + inMax : Integer; + inValue : Integer; + inTrackStyle : XPTrackStyle; + inLit : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetTrackDefaultDimensions + + This routine returns a track's default smaller dimension; all tracks are + scalable in the larger dimension. It also returns whether a track can be + lit. + } + PROCEDURE XPGetTrackDefaultDimensions( + inStyle : XPTrackStyle; + outWidth : PInteger; + outCanBeLit : PInteger); + cdecl; external XPWIDGETS.DLL; + + { + XPGetTrackMetrics + + This routine returns the metrics of a track. If you want to write UI code + to manipulate a track, this routine helps you know where the mouse + locations are. For most other elements, the rectangle the element is drawn + in is enough information. However, the scrollbar drawing routine does some + automatic placement; this routine lets you know where things ended up. You + pass almost everything you would pass to the draw routine. You get out the + orientation, and other useful stuff. + + Besides orientation, you get five dimensions for the five parts of a + scrollbar, which are the down button, down area (area before the thumb), + the thumb, and the up area and button. For horizontal scrollers, the left + button decreases; for vertical scrollers, the top button decreases. + } + PROCEDURE XPGetTrackMetrics( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inMin : Integer; + inMax : Integer; + inValue : Integer; + inTrackStyle : XPTrackStyle; + outIsVertical : PInteger; + outDownBtnSize : PInteger; + outDownPageSize : PInteger; + outThumbSize : PInteger; + outUpPageSize : PInteger; + outUpBtnSize : PInteger); + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgetDefs.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgetDefs.pas new file mode 100644 index 0000000..1cc342f --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgetDefs.pas @@ -0,0 +1,427 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgetDefs; +INTERFACE + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * WIDGET DEFINITIONS + ___________________________________________________________________________} +{ + A widget is a call-back driven screen entity like a push-button, window, + text entry field, etc. + + Use the widget API to create widgets of various classes. You can nest them + into trees of widgets to create complex user interfaces. +} + + +TYPE + { + XPWidgetID + + A Widget ID is an opaque unique non-zero handle identifying your widget. + Use 0 to specify "no widget". This type is defined as wide enough to hold a + pointer. You receive a widget ID when you create a new widget and then use + that widget ID to further refer to the widget. + } + XPWidgetID = pointer; + PXPWidgetID = ^XPWidgetID; + + { + XPWidgetPropertyID + + Properties are values attached to instances of your widgets. A property is + identified by a 32-bit ID and its value is the width of a pointer. + + Each widget instance may have a property or not have it. When you set a + property on a widget for the first time, the property is added to the + widget; it then stays there for the life of the widget. + + Some property IDs are predefined by the widget package; you can make up + your own property IDs as well. + } + XPWidgetPropertyID = ( + { A window's refcon is an opaque value used by client code to find other data} + { based on it. } + xpProperty_Refcon = 0 + + { These properties are used by the utlities to implement dragging. } + ,xpProperty_Dragging = 1 + + ,xpProperty_DragXOff = 2 + + ,xpProperty_DragYOff = 3 + + { Is the widget hilited? (For widgets that support this kind of thing.) } + ,xpProperty_Hilited = 4 + + { Is there a C++ object attached to this widget? } + ,xpProperty_Object = 5 + + { If this property is 1, the widget package will use OpenGL to restrict } + { drawing to the Wiget's exposed rectangle. } + ,xpProperty_Clip = 6 + + { Is this widget enabled (for those that have a disabled state too)? } + ,xpProperty_Enabled = 7 + + { NOTE: Property IDs 1 - 999 are reserved for the widgets library. } + { } + { NOTE: Property IDs 1000 - 9999 are allocated to the standard widget classes} + { provided with the library. } + { } + { Properties 1000 - 1099 are for widget class 0, 1100 - 1199 for widget class} + { 1, etc. } + ,xpProperty_UserStart = 10000 + + ); + PXPWidgetPropertyID = ^XPWidgetPropertyID; + + { + XPMouseState_t + + When the mouse is clicked or dragged, a pointer to this structure is passed + to your widget function. + } + XPMouseState_t = RECORD + x : Integer; + y : Integer; + { Mouse Button number, left = 0 (right button not yet supported. } + button : Integer; +{$IFDEF XPLM200} + { Scroll wheel delta (button in this case would be the wheel axis number). } + delta : Integer; +{$ENDIF XPLM200} + END; + PXPMouseState_t = ^XPMouseState_t; + + { + XPKeyState_t + + When a key is pressed, a pointer to this struct is passed to your widget + function. + } + XPKeyState_t = RECORD + { The ASCII key that was pressed. WARNING: this may be 0 for some non-ASCII } + { key sequences. } + key : XPLMChar; + { The flags. Make sure to check this if you only want key-downs! } + flags : XPLMKeyFlags; + { The virtual key code for the key } + vkey : XPLMChar; + END; + PXPKeyState_t = ^XPKeyState_t; + + { + XPWidgetGeometryChange_t + + This structure contains the deltas for your widget's geometry when it + changes. + } + XPWidgetGeometryChange_t = RECORD + dx : Integer; + { +Y = the widget moved up } + dy : Integer; + dwidth : Integer; + dheight : Integer; + END; + PXPWidgetGeometryChange_t = ^XPWidgetGeometryChange_t; + + { + XPDispatchMode + + The dispatching modes describe how the widgets library sends out messages. + Currently there are three modes: + } + XPDispatchMode = ( + { The message will only be sent to the target widget. } + xpMode_Direct = 0 + + { The message is sent to the target widget, then up the chain of parents } + { until the message is handled or a parentless widget is reached. } + ,xpMode_UpChain = 1 + + { The message is sent to the target widget and then all of its children } + { recursively depth-first. } + ,xpMode_Recursive = 2 + + { The message is snet just to the target, but goes to every callback, even if} + { it is handled. } + ,xpMode_DirectAllCallbacks = 3 + + { The message is only sent to the very first handler even if it is not } + { accepted. (This is really only useful for some internal widget library } + { functions.) } + ,xpMode_Once = 4 + + ); + PXPDispatchMode = ^XPDispatchMode; + + { + XPWidgetClass + + Widget classes define predefined widget types. A widget class basically + specifies from a library the widget function to be used for the widget. + Most widgets can be made right from classes. + } + XPWidgetClass = Integer; + PXPWidgetClass = ^XPWidgetClass; + +CONST + { An unspecified widget class. Other widget classes are in } + { XPStandardWidgets.h } + xpWidgetClass_None = 0; + +{___________________________________________________________________________ + * WIDGET MESSAGES + ___________________________________________________________________________} + + { + XPWidgetMessage + + Widgets receive 32-bit messages indicating what action is to be taken or + notifications of events. The list of messages may be expanded. + } +TYPE + XPWidgetMessage = ( + { No message, should not be sent. } + xpMsg_None = 0 + + { The create message is sent once per widget that is created with your widget} + { function and once for any widget that has your widget function attached. } + { } + { Dispatching: Direct } + { } + { Param 1: 1 if you are being added as a subclass, 0 if the widget is first } + { being created. } + ,xpMsg_Create = 1 + + { The destroy message is sent once for each message that is destroyed that } + { has your widget function. } + { } + { Dispatching: Direct for all } + { } + { Param 1: 1 if being deleted by a recursive delete to the parent, 0 for } + { explicit deletion. } + ,xpMsg_Destroy = 2 + + { The paint message is sent to your widget to draw itself. The paint message } + { is the bare-bones message; in response you must draw yourself, draw your } + { children, set up clipping and culling, check for visibility, etc. If you } + { don't want to do all of this, ignore the paint message and a draw message } + { (see below) will be sent to you. } + { } + { Dispatching: Direct } + ,xpMsg_Paint = 3 + + { The draw message is sent to your widget when it is time to draw yourself. } + { OpenGL will be set up to draw in 2-d global screen coordinates, but you } + { should use the XPLM to set up OpenGL state. } + { } + { Dispatching: Direct } + ,xpMsg_Draw = 4 + + { The key press message is sent once per key that is pressed. The first } + { parameter is the type of key code (integer or char) and the second is the } + { code itself. By handling this event, you consume the key stroke. } + { } + { Handling this message 'consumes' the keystroke; not handling it passes it } + { to your parent widget. } + { } + { Dispatching: Up Chain } + { } + { Param 1: A pointer to an XPKeyState_t structure with the keystroke. } + ,xpMsg_KeyPress = 5 + + { Keyboard focus is being given to you. By handling this message you accept } + { keyboard focus. The first parameter will be one if a child of yours gave up} + { focus to you, 0 if someone set focus on you explicitly. } + { } + { Handling this message accepts focus; not handling refuses focus. } + { } + { Dispatching: direct } + { } + { Param 1: 1 if you are gaining focus because your child is giving it up, 0 } + { if someone is explicitly giving you focus. } + ,xpMsg_KeyTakeFocus = 6 + + { Keyboard focus is being taken away from you. The first parameter will be } + { one if you are losing focus because another widget is taking it, or 0 if } + { someone called the API to make you lose focus explicitly. } + { } + { Dispatching: Direct } + { } + { Param 1: 1 if focus is being taken by another widget, 0 if code requested } + { to remove focus. } + ,xpMsg_KeyLoseFocus = 7 + + { You receive one mousedown event per click with a mouse-state structure } + { pointed to by parameter 1, by accepting this you eat the click, otherwise } + { your parent gets it. You will not receive drag and mouse up messages if you} + { do not accept the down message. } + { } + { Handling this message consumes the mouse click, not handling it passes it } + { to the next widget. You can act 'transparent' as a window by never handling} + { moues clicks to certain areas. } + { } + { Dispatching: Up chain NOTE: Technically this is direct dispatched, but the } + { widgets library will shop it to each widget until one consumes the click, } + { making it effectively "up chain". } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseDown = 8 + + { You receive a series of mouse drag messages (typically one per frame in the} + { sim) as the mouse is moved once you have accepted a mouse down message. } + { Parameter one points to a mouse-state structure describing the mouse } + { location. You will continue to receive these until the mouse button is } + { released. You may receive multiple mouse state messages with the same mouse} + { position. You will receive mouse drag events even if the mouse is dragged } + { out of your current or original bounds at the time of the mouse down. } + { } + { Dispatching: Direct } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseDrag = 9 + + { The mouseup event is sent once when the mouse button is released after a } + { drag or click. You only receive this message if you accept the mouseDown } + { message. Parameter one points to a mouse state structure. } + { } + { Dispatching: Direct } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseUp = 10 + + { Your geometry or a child's geometry is being changed. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the original reshaped target. } + { } + { Param 2: A pointer to a XPWidgetGeometryChange_t struct describing the } + { change. } + ,xpMsg_Reshape = 11 + + { Your exposed area has changed. } + { } + { Dispatching: Direct } + ,xpMsg_ExposedChanged = 12 + + { A child has been added to you. The child's ID is passed in parameter one. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of the child being added. } + ,xpMsg_AcceptChild = 13 + + { A child has been removed from to you. The child's ID is passed in parameter} + { one. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of the child being removed. } + ,xpMsg_LoseChild = 14 + + { You now have a new parent, or have no parent. The parent's ID is passed in,} + { or 0 for no parent. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of your parent } + ,xpMsg_AcceptParent = 15 + + { You or a child has been shown. Note that this does not include you being } + { shown because your parent was shown, you were put in a new parent, your } + { root was shown, etc. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the shown widget. } + ,xpMsg_Shown = 16 + + { You have been hidden. See limitations above. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the hidden widget. } + ,xpMsg_Hidden = 17 + + { Your descriptor has changed. } + { } + { Dispatching: Direct } + ,xpMsg_DescriptorChanged = 18 + + { A property has changed. Param 1 contains the property ID. } + { } + { Dispatching: Direct } + { } + { Param 1: The Property ID being changed. } + { } + { Param 2: The new property value } + ,xpMsg_PropertyChanged = 19 + +{$IFDEF XPLM200} + { The mouse wheel has moved. } + { } + { Return 1 to consume the mouse wheel move, or 0 to pass the message to a } + { parent. Dispatching: Up chain } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseWheel = 20 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { The cursor is over your widget. If you consume this message, change the } + { XPLMCursorStatus value to indicate the desired result, with the same rules } + { as in XPLMDisplay.h. } + { } + { Return 1 to consume this message, 0 to pass it on. } + { } + { Dispatching: Up chain Param 1: A pointer to an XPMouseState_t struct } + { containing the mouse status. } + { } + { Param 2: A pointer to a XPLMCursorStatus - set this to the cursor result } + { you desire. } + ,xpMsg_CursorAdjust = 21 +{$ENDIF XPLM200} + + { NOTE: Message IDs 1000 - 9999 are allocated to the standard widget classes } + { provided with the library with 1000 - 1099 for widget class 0, 1100 - 1199 } + { for widget class 1, etc. Message IDs 10,000 and beyond are for plugin use. } + ,xpMsg_UserStart = 10000 + + ); + PXPWidgetMessage = ^XPWidgetMessage; + +{___________________________________________________________________________ + * WIDGET CALLBACK FUNCTION + ___________________________________________________________________________} + + { + XPWidgetFunc_t + + This function defines your custom widget's behavior. It will be called by + the widgets library to send messages to your widget. The message and widget + ID are passed in, as well as two ptr-width signed parameters whose meaning + varies with the message. Return 1 to indicate that you have processed the + message, 0 to indicate that you have not. For any message that is not + understood, return 0. + } +TYPE + XPWidgetFunc_t = FUNCTION( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; cdecl; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgetUtils.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgetUtils.pas new file mode 100644 index 0000000..9621126 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgetUtils.pas @@ -0,0 +1,197 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgetUtils; +INTERFACE +{ + ## USAGE NOTES + + The XPWidgetUtils library contains useful functions that make writing and + using widgets less of a pain. + + One set of functions are the widget behavior functions. These functions + each add specific useful behaviors to widgets. They can be used in two + manners: + + 1. You can add a widget behavior function to a widget as a callback proc + using the XPAddWidgetCallback function. The widget will gain that + behavior. Remember that the last function you add has highest priority. + You can use this to change or augment the behavior of an existing + finished widget. + 2. You can call a widget function from inside your own widget function. + This allows you to include useful behaviors in custom-built widgets. A + number of the standard widgets get their behavior from this library. To + do this, call the behavior function from your function first. If it + returns 1, that means it handled the event and you don't need to; simply + return 1. +} + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * GENERAL UTILITIES + ___________________________________________________________________________} + + + { + XPWidgetCreate_t + + This structure contains all of the parameters needed to create a wiget. It + is used with XPUCreateWidgets to create widgets in bulk from an array. All + parameters correspond to those of XPCreateWidget except for the container + index. + + If the container index is equal to the index of a widget in the array, the + widget in the array passed to XPUCreateWidgets is used as the parent of + this widget. Note that if you pass an index greater than your own position + in the array, the parent you are requesting will not exist yet. + + If the container index is NO_PARENT, the parent widget is specified as + NULL. If the container index is PARAM_PARENT, the widget passed into + XPUCreateWidgets is used. + } +TYPE + XPWidgetCreate_t = RECORD + left : Integer; + top : Integer; + right : Integer; + bottom : Integer; + visible : Integer; + descriptor : XPLMString; + { Whether ethis widget is a root wiget } + isRoot : Integer; + { The index of the widget to contain within, or a constant } + containerIndex : Integer; + widgetClass : XPWidgetClass; + END; + PXPWidgetCreate_t = ^XPWidgetCreate_t; + +CONST + NO_PARENT = -1; + + PARAM_PARENT = -2; + + + { + XPUCreateWidgets + + This function creates a series of widgets from a table (see + XPCreateWidget_t above). Pass in an array of widget creation structures and + an array of widget IDs that will receive each widget. + + Widget parents are specified by index into the created widget table, + allowing you to create nested widget structures. You can create multiple + widget trees in one table. Generally you should create widget trees from + the top down. + + You can also pass in a widget ID that will be used when the widget's parent + is listed as PARAM_PARENT; this allows you to embed widgets created with + XPUCreateWidgets in a widget created previously. + } + PROCEDURE XPUCreateWidgets( + inWidgetDefs : PXPWidgetCreate_t; + inCount : Integer; + inParamParent : XPWidgetID; + ioWidgets : PXPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPUMoveWidgetBy + + Simply moves a widget by an amount, +x = right, +y=up, without resizing the + widget. + } + PROCEDURE XPUMoveWidgetBy( + inWidget : XPWidgetID; + inDeltaX : Integer; + inDeltaY : Integer); + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * LAYOUT MANAGERS + ___________________________________________________________________________} +{ + The layout managers are widget behavior functions for handling where + widgets move. Layout managers can be called from a widget function or + attached to a widget later. +} + + + { + XPUFixedLayout + + This function causes the widget to maintain its children in fixed position + relative to itself as it is resized. Use this on the top level 'window' + widget for your window. + } + FUNCTION XPUFixedLayout( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * WIDGET PROC BEHAVIORS + ___________________________________________________________________________} +{ + These widget behavior functions add other useful behaviors to widgets. + These functions cannot be attached to a widget; they must be called from + your widget function. +} + + + { + XPUSelectIfNeeded + + This causes the widget to bring its window to the foreground if it is not + already. inEatClick specifies whether clicks in the background should be + consumed by bringin the window to the foreground. + } + FUNCTION XPUSelectIfNeeded( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inEatClick : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPUDefocusKeyboard + + This causes a click in the widget to send keyboard focus back to X-Plane. + This stops editing of any text fields, etc. + } + FUNCTION XPUDefocusKeyboard( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inEatClick : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPUDragWidget + + XPUDragWidget drags the widget in response to mouse clicks. Pass in not + only the event, but the global coordinates of the drag region, which might + be a sub-region of your widget (for example, a title bar). + } + FUNCTION XPUDragWidget( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgets.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgets.pas new file mode 100644 index 0000000..46ae542 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/Widgets/XPWidgets.pas @@ -0,0 +1,527 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgets; +INTERFACE +{ + ## THEORY OF OPERATION AND NOTES + + Widgets are persistent view 'objects' for X-Plane. A widget is an object + referenced by its opaque handle (widget ID) and the APIs in this file. You + cannot access the widget's guts directly. Every Widget has the following + intrinsic data: + + - A bounding box defined in global screen coordinates with 0,0 in the + bottom left and +y = up, +x = right. + - A visible box, which is the intersection of the bounding box with the + widget's parents visible box. + - Zero or one parent widgets. (Always zero if the widget is a root widget. + - Zero or more child widgets. + - Whether the widget is a root. Root widgets are the top level plugin + windows. + - Whether the widget is visible. + - A text string descriptor, whose meaning varies from widget to widget. + - An arbitrary set of 32 bit integral properties defined by 32-bit integral + keys. This is how specific widgets store specific data. + - A list of widget callbacks proc that implements the widgets behaviors. + + The Widgets library sends messages to widgets to request specific behaviors + or notify the widget of things. + + Widgets may have more than one callback function, in which case messages + are sent to the most recently added callback function until the message is + handled. Messages may also be sent to parents or children; see the + XPWidgetDefs.h header file for the different widget message dispatching + functions. By adding a callback function to a window you can 'subclass' its + behavior. + + A set of standard widgets are provided that serve common UI purposes. You + can also customize or implement entirely custom widgets. + + Widgets are different than other view hierarchies (most notably Win32, + which they bear a striking resemblance to) in the following ways: + + - Not all behavior can be patched. State that is managed by the XPWidgets + DLL and not by individual widgets cannot be customized. + - All coordinates are in global screen coordinates. Coordinates are not + relative to an enclosing widget, nor are they relative to a display + window. + - Widget messages are always dispatched synchronously, and there is no + concept of scheduling an update or a dirty region. Messages originate + from X-Plane as the sim cycle goes by. Since X-Plane is constantly + redrawing, so are widgets; there is no need to mark a part of a widget as + 'needing redrawing' because redrawing happens frequently whether the + widget needs it or not. + - Any widget may be a 'root' widget, causing it to be drawn; there is no + relationship between widget class and rootness. Root widgets are + imlemented as XPLMDisply windows. +} + +USES + XPWidgetDefs, XPLMDisplay; + {$A4} +{___________________________________________________________________________ + * WIDGET CREATION AND MANAGEMENT + ___________________________________________________________________________} + + { + XPCreateWidget + + This function creates a new widget and returns the new widget's ID to you. + If the widget creation fails for some reason, it returns NULL. Widget + creation will fail either if you pass a bad class ID or if there is not + adequate memory. + + Input Parameters: + + - Top, left, bottom, and right in global screen coordinates defining the + widget's location on the screen. + - inVisible is 1 if the widget should be drawn, 0 to start the widget as + hidden. + - inDescriptor is a null terminated string that will become the widget's + descriptor. + - inIsRoot is 1 if this is going to be a root widget, 0 if it will not be. + - inContainer is the ID of this widget's container. It must be 0 for a root + widget. for a non-root widget, pass the widget ID of the widget to place + this widget within. If this widget is not going to start inside another + widget, pass 0; this new widget will then just be floating off in space + (and will not be drawn until it is placed in a widget. + - inClass is the class of the widget to draw. Use one of the predefined + class-IDs to create a standard widget. + + A note on widget embedding: a widget is only called (and will be drawn, + etc.) if it is placed within a widget that will be called. Root widgets are + always called. So it is possible to have whole chains of widgets that are + simply not called. You can preconstruct widget trees and then place them + into root widgets later to activate them if you wish. + } + FUNCTION XPCreateWidget( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inVisible : Integer; + inDescriptor : XPLMString; + inIsRoot : Integer; + inContainer : XPWidgetID; + inClass : XPWidgetClass) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPCreateCustomWidget + + This function is the same as XPCreateWidget except that instead of passing + a class ID, you pass your widget callback function pointer defining the + widget. Use this function to define a custom widget. All parameters are the + same as XPCreateWidget, except that the widget class has been replaced with + the widget function. + } + FUNCTION XPCreateCustomWidget( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inVisible : Integer; + inDescriptor : XPLMString; + inIsRoot : Integer; + inContainer : XPWidgetID; + inCallback : XPWidgetFunc_t) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPDestroyWidget + + This class destroys a widget. Pass in the ID of the widget to kill. If you + pass 1 for inDestroyChilren, the widget's children will be destroyed first, + then this widget will be destroyed. (Furthermore, the widget's children + will be destroyed with the inDestroyChildren flag set to 1, so the + destruction will recurse down the widget tree.) If you pass 0 for this + flag, the child widgets will simply end up with their parent set to 0. + } + PROCEDURE XPDestroyWidget( + inWidget : XPWidgetID; + inDestroyChildren : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPSendMessageToWidget + + This sends any message to a widget. You should probably not go around + simulating the predefined messages that the widgets library defines for + you. You may however define custom messages for your widgets and send them + with this method. + + This method supports several dispatching patterns; see XPDispatchMode for + more info. The function returns 1 if the message was handled, 0 if it was + not. + + For each widget that receives the message (see the dispatching modes), each + widget function from the most recently installed to the oldest one receives + the message in order until it is handled. + } + FUNCTION XPSendMessageToWidget( + inWidget : XPWidgetID; + inMessage : XPWidgetMessage; + inMode : XPDispatchMode; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * WIDGET POSITIONING AND VISIBILITY + ___________________________________________________________________________} + + { + XPPlaceWidgetWithin + + This function changes which container a widget resides in. You may NOT use + this function on a root widget! inSubWidget is the widget that will be + moved. Pass a widget ID in inContainer to make inSubWidget be a child of + inContainer. It will become the last/closest widget in the container. Pass + 0 to remove the widget from any container. Any call to this other than + passing the widget ID of the old parent of the affected widget will cause + the widget to be removed from its old parent. Placing a widget within its + own parent simply makes it the last widget. + + NOTE: this routine does not reposition the sub widget in global + coordinates. If the container has layout management code, it will + reposition the subwidget for you, otherwise you must do it with + SetWidgetGeometry. + } + PROCEDURE XPPlaceWidgetWithin( + inSubWidget : XPWidgetID; + inContainer : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPCountChildWidgets + + This routine returns the number of widgets another widget contains. + } + FUNCTION XPCountChildWidgets( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetNthChildWidget + + This routine returns the widget ID of a child widget by index. Indexes are + 0 based, from 0 to one minus the number of widgets in the parent, + inclusive. If the index is invalid, 0 is returned. + } + FUNCTION XPGetNthChildWidget( + inWidget : XPWidgetID; + inIndex : Integer) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPGetParentWidget + + Returns the parent of a widget, or 0 if the widget has no parent. Root + widgets never have parents and therefore always return 0. + } + FUNCTION XPGetParentWidget( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPShowWidget + + This routine makes a widget visible if it is not already. Note that if a + widget is not in a rooted widget hierarchy or one of its parents is not + visible, it will still not be visible to the user. + } + PROCEDURE XPShowWidget( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPHideWidget + + Makes a widget invisible. See XPShowWidget for considerations of when a + widget might not be visible despite its own visibility state. + } + PROCEDURE XPHideWidget( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPIsWidgetVisible + + This returns 1 if a widget is visible, 0 if it is not. Note that this + routine takes into consideration whether a parent is invisible. Use this + routine to tell if the user can see the widget. + } + FUNCTION XPIsWidgetVisible( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPFindRootWidget + + Returns the Widget ID of the root widget that contains the passed in widget + or NULL if the passed in widget is not in a rooted hierarchy. + } + FUNCTION XPFindRootWidget( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPBringRootWidgetToFront + + This routine makes the specified widget be in the front most widget + hierarchy. If this widget is a root widget, its widget hierarchy comes to + front, otherwise the widget's root is brought to the front. If this widget + is not in an active widget hiearchy (e.g. there is no root widget at the + top of the tree), this routine does nothing. + } + PROCEDURE XPBringRootWidgetToFront( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPIsWidgetInFront + + This routine returns true if this widget's hierarchy is the front most + hierarchy. It returns false if the widget's hierarchy is not in front, or + if the widget is not in a rooted hierarchy. + } + FUNCTION XPIsWidgetInFront( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetGeometry + + This routine returns the bounding box of a widget in global coordinates. + Pass NULL for any parameter you are not interested in. + } + PROCEDURE XPGetWidgetGeometry( + inWidget : XPWidgetID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPSetWidgetGeometry + + This function changes the bounding box of a widget. + } + PROCEDURE XPSetWidgetGeometry( + inWidget : XPWidgetID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetForLocation + + Given a widget and a location, this routine returns the widget ID of the + child of that widget that owns that location. If inRecursive is true then + this will return a child of a child of a widget as it tries to find the + deepest widget at that location. If inVisibleOnly is true, then only + visible widgets are considered, otherwise all widgets are considered. The + widget ID passed for inContainer will be returned if the location is in + that widget but not in a child widget. 0 is returned if the location is not + in the container. + + NOTE: if a widget's geometry extends outside its parents geometry, it will + not be returned by this call for mouse locations outside the parent + geometry. The parent geometry limits the child's eligibility for mouse + location. + } + FUNCTION XPGetWidgetForLocation( + inContainer : XPWidgetID; + inXOffset : Integer; + inYOffset : Integer; + inRecursive : Integer; + inVisibleOnly : Integer) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetExposedGeometry + + This routine returns the bounds of the area of a widget that is completely + within its parent widgets. Since a widget's bounding box can be outside its + parent, part of its area will not be elligible for mouse clicks and should + not draw. Use XPGetWidgetGeometry to find out what area defines your + widget's shape, but use this routine to find out what area to actually draw + into. Note that the widget library does not use OpenGL clipping to keep + frame rates up, although you could use it internally. + } + PROCEDURE XPGetWidgetExposedGeometry( + inWidgetID : XPWidgetID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * ACCESSING WIDGET DATA + ___________________________________________________________________________} + + { + XPSetWidgetDescriptor + + Every widget has a descriptor, which is a text string. What the text string + is used for varies from widget to widget; for example, a push button's text + is its descriptor, a caption shows its descriptor, and a text field's + descriptor is the text being edited. In other words, the usage for the text + varies from widget to widget, but this API provides a universal and + convenient way to get at it. While not all UI widgets need their + descriptor, many do. + } + PROCEDURE XPSetWidgetDescriptor( + inWidget : XPWidgetID; + inDescriptor : XPLMString); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetDescriptor + + This routine returns the widget's descriptor. Pass in the length of the + buffer you are going to receive the descriptor in. The descriptor will be + null terminated for you. This routine returns the length of the actual + descriptor; if you pass NULL for outDescriptor, you can get the + descriptor's length without getting its text. If the length of the + descriptor exceeds your buffer length, the buffer will not be null + terminated (this routine has 'strncpy' semantics). + } + FUNCTION XPGetWidgetDescriptor( + inWidget : XPWidgetID; + outDescriptor : XPLMString; + inMaxDescLength : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetUnderlyingWindow + + Returns the window (from the XPLMDisplay API) that backs your widget + window. If you have opted in to modern windows, via a call to + XPLMEnableFeature("XPLM_USE_NATIVE_WIDGET_WINDOWS", 1), you can use the + returned window ID for display APIs like XPLMSetWindowPositioningMode(), + allowing you to pop the widget window out into a real OS window, or move it + into VR. + } + FUNCTION XPGetWidgetUnderlyingWindow( + inWidget : XPWidgetID) : XPLMWindowID; + cdecl; external XPWIDGETS.DLL; + + { + XPSetWidgetProperty + + This function sets a widget's property. Properties are arbitrary values + associated by a widget by ID. + } + PROCEDURE XPSetWidgetProperty( + inWidget : XPWidgetID; + inProperty : XPWidgetPropertyID; + inValue : intptr_t); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetProperty + + This routine returns the value of a widget's property, or 0 if the property + is not defined. If you need to know whether the property is defined, pass a + pointer to an int for inExists; the existence of that property will be + returned in the int. Pass NULL for inExists if you do not need this + information. + } + FUNCTION XPGetWidgetProperty( + inWidget : XPWidgetID; + inProperty : XPWidgetPropertyID; + inExists : PInteger) : intptr_t; { Can be nil } + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * KEYBOARD MANAGEMENT + ___________________________________________________________________________} + + { + XPSetKeyboardFocus + + Controls which widget will receive keystrokes. Pass the widget ID of the + widget to get the keys. Note that if the widget does not care about + keystrokes, they will go to the parent widget, and if no widget cares about + them, they go to X-Plane. + + If you set the keyboard focus to widget ID 0, X-Plane gets keyboard focus. + + This routine returns the widget ID that ended up with keyboard focus, or 0 + for X-Plane. + + Keyboard focus is not changed if the new widget will not accept it. For + setting to X-Plane, keyboard focus is always accepted. + } + FUNCTION XPSetKeyboardFocus( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPLoseKeyboardFocus + + This causes the specified widget to lose focus; focus is passed to its + parent, or the next parent that will accept it. This routine does nothing + if this widget does not have focus. + } + PROCEDURE XPLoseKeyboardFocus( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetWithFocus + + This routine returns the widget that has keyboard focus, or 0 if X-Plane + has keyboard focus or some other plugin window that does not have widgets + has focus. + } + FUNCTION XPGetWidgetWithFocus: XPWidgetID; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * CREATING CUSTOM WIDGETS + ___________________________________________________________________________} + + { + XPAddWidgetCallback + + This function adds a new widget callback to a widget. This widget callback + supercedes any existing ones and will receive messages first; if it does + not handle messages they will go on to be handled by pre-existing widgets. + + The widget function will remain on the widget for the life of the widget. + The creation message will be sent to the new callback immediately with the + widget ID, and the destruction message will be sent before the other widget + function receives a destruction message. + + This provides a way to 'subclass' an existing widget. By providing a second + hook that only handles certain widget messages, you can customize or extend + widget behavior. + } + PROCEDURE XPAddWidgetCallback( + inWidget : XPWidgetID; + inNewCallback : XPWidgetFunc_t); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetClassFunc + + Given a widget class, this function returns the callbacks that power that + widget class. + } + FUNCTION XPGetWidgetClassFunc( + inWidgetClass : XPWidgetClass) : XPWidgetFunc_t; + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMCamera.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMCamera.pas new file mode 100644 index 0000000..ad76fa4 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMCamera.pas @@ -0,0 +1,155 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMCamera; +INTERFACE +{ + The XPLMCamera APIs allow plug-ins to control the camera angle in X-Plane. + This has a number of applications, including but not limited to: + + - Creating new views (including dynamic/user-controllable views) for the + user. + - Creating applications that use X-Plane as a renderer of scenery, + aircrafts, or both. + + The camera is controlled via six parameters: a location in OpenGL + coordinates and pitch, roll and yaw, similar to an airplane's position. + OpenGL coordinate info is described in detail in the XPLMGraphics + documentation; generally you should use the XPLMGraphics routines to + convert from world to local coordinates. The camera's orientation starts + facing level with the ground directly up the negative-Z axis (approximately + north) with the horizon horizontal. It is then rotated clockwise for yaw, + pitched up for positive pitch, and rolled clockwise around the vector it is + looking along for roll. + + You control the camera either either until the user selects a new view or + permanently (the later being similar to how UDP camera control works). You + control the camera by registering a callback per frame from which you + calculate the new camera positions. This guarantees smooth camera motion. + + Use the XPLMDataAccess APIs to get information like the position of the + aircraft, etc. for complex camera positioning. + + Note: if your goal is to move the virtual pilot in the cockpit, this API is + not needed; simply update the datarefs for the pilot's head position. + + For custom exterior cameras, set the camera's mode to an external view + first to get correct sound and 2-d panel behavior. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * CAMERA CONTROL + ___________________________________________________________________________} + + { + XPLMCameraControlDuration + + This enumeration states how long you want to retain control of the camera. + You can retain it indefinitely or until the user selects a new view. + } +TYPE + XPLMCameraControlDuration = ( + { Control the camera until the user picks a new view. } + xplm_ControlCameraUntilViewChanges = 1 + + { Control the camera until your plugin is disabled or another plugin forcably} + { takes control. } + ,xplm_ControlCameraForever = 2 + + ); + PXPLMCameraControlDuration = ^XPLMCameraControlDuration; + + { + XPLMCameraPosition_t + + This structure contains a full specification of the camera. X, Y, and Z are + the camera's position in OpenGL coordiantes; pitch, roll, and yaw are + rotations from a camera facing flat north in degrees. Positive pitch means + nose up, positive roll means roll right, and positive yaw means yaw right, + all in degrees. Zoom is a zoom factor, with 1.0 meaning normal zoom and 2.0 + magnifying by 2x (objects appear larger). + } + XPLMCameraPosition_t = RECORD + x : Single; + y : Single; + z : Single; + pitch : Single; + heading : Single; + roll : Single; + zoom : Single; + END; + PXPLMCameraPosition_t = ^XPLMCameraPosition_t; + + { + XPLMCameraControl_f + + You use an XPLMCameraControl function to provide continuous control over + the camera. You are passed in a structure in which to put the new camera + position; modify it and return 1 to reposition the camera. Return 0 to + surrender control of the camera; camera control will be handled by X-Plane + on this draw loop. The contents of the structure as you are called are + undefined. + + If X-Plane is taking camera control away from you, this function will be + called with inIsLosingControl set to 1 and ioCameraPosition NULL. + } + XPLMCameraControl_f = FUNCTION( + outCameraPosition : PXPLMCameraPosition_t; { Can be nil } + inIsLosingControl : Integer; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMControlCamera + + This function repositions the camera on the next drawing cycle. You must + pass a non-null control function. Specify in inHowLong how long you'd like + control (indefinitely or until a new view mode is set by the user). + } + PROCEDURE XPLMControlCamera( + inHowLong : XPLMCameraControlDuration; + inControlFunc : XPLMCameraControl_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMDontControlCamera + + This function stops you from controlling the camera. If you have a camera + control function, it will not be called with an inIsLosingControl flag. + X-Plane will control the camera on the next cycle. + + For maximum compatibility you should not use this routine unless you are in + posession of the camera. + } + PROCEDURE XPLMDontControlCamera; + cdecl; external XPLM_DLL; + + { + XPLMIsCameraBeingControlled + + This routine returns 1 if the camera is being controlled, zero if it is + not. If it is and you pass in a pointer to a camera control duration, the + current control duration will be returned. + } + FUNCTION XPLMIsCameraBeingControlled( + outCameraControlDuration: PXPLMCameraControlDuration) : Integer; { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMReadCameraPosition + + This function reads the current camera position. + } + PROCEDURE XPLMReadCameraPosition( + outCameraPosition : PXPLMCameraPosition_t); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDataAccess.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDataAccess.pas new file mode 100644 index 0000000..1ad210e --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDataAccess.pas @@ -0,0 +1,690 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDataAccess; +INTERFACE +{ + The data access API gives you a generic, flexible, high performance way to + read and write data to and from X-Plane and other plug-ins. For example, + this API allows you to read and set the nav radios, get the plane location, + determine the current effective graphics frame rate, etc. + + The data access APIs are the way that you read and write data from the sim + as well as other plugins. + + The API works using opaque data references. A data reference is a source of + data; you do not know where it comes from, but once you have it you can + read the data quickly and possibly write it. + + Dataref Lookup + -------------- + + Data references are identified by verbose, permanent string names; by + convention these names use path separates to form a hierarchy of datarefs, + e.g. (sim/cockpit/radios/nav1_freq_hz). The actual opaque numeric value of + the data reference, as returned by the XPLM API, is implementation defined + and changes each time X-Plane is launched; therefore you need to look up + the dataref by path every time your plugin runs. + + The task of looking up a data reference is relatively expensive; look up + your data references once based on the verbose path strings, and save the + opaque data reference value for the duration of your plugin's operation. + Reading and writing data references is relatively fast (the cost is + equivalent to two function calls through function pointers). + + X-Plane publishes over 4000 datarefs; a complete list may be found in the + reference section of the SDK online documentation (from the SDK home page, + choose Documentation). + + Dataref Types + ------------- + + A note on typing: you must know the correct data type to read and write. + APIs are provided for reading and writing data in a number of ways. You can + also double check the data type for a data ref. Automatic type conversion + is not done for you. + + Dataref types are a set, e.g. a dataref can be more than one type. When + this happens, you can choose which API you want to use to read. For + example, it is not uncommon for a dataref to be of type float and double. + This means you can use either XPLMGetDatad or XPLMGetDataf to read it. + + Creating New Datarefs + --------------------- + + X-Plane provides datarefs that come with the sim, but plugins can also + create their own datarefs. A plugin creates a dataref by registering + function callbacks to read and write the dataref. The XPLM will call your + plugin each time some other plugin (or X-Plane) tries to read or write the + dataref. You must provide a read (and optional write) callback for each + data type you support. + + A note for plugins sharing data with other plugins: the load order of + plugins is not guaranteed. To make sure that every plugin publishing data + has published their data references before other plugins try to subscribe, + publish your data references in your start routine but resolve them the + first time your 'enable' routine is called, or the first time they are + needed in code. + + When a plugin that created a dataref is unloaded, it becomes "orphaned". + The dataref handle continues to be usable, but the dataref is not writable, + and reading it will always return 0 (or 0 items for arrays). If the plugin + is reloaded and re-registers the dataref, the handle becomes un-orphaned + and works again. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * READING AND WRITING DATA + ___________________________________________________________________________} +{ + These routines allow you to access data from within X-Plane and sometimes + modify it. +} + + +TYPE + { + XPLMDataRef + + A data ref is an opaque handle to data provided by the simulator or another + plugin. It uniquely identifies one variable (or array of variables) over + the lifetime of your plugin. You never hard code these values; you always + get them from XPLMFindDataRef. + } + XPLMDataRef = pointer; + PXPLMDataRef = ^XPLMDataRef; + + { + XPLMDataTypeID + + This is an enumeration that defines the type of the data behind a data + reference. This allows you to sanity check that the data type matches what + you expect. But for the most part, you will know the type of data you are + expecting from the online documentation. + + Data types each take a bit field; it is legal to have a single dataref be + more than one type of data. Whe this happens, you can pick any matching + get/set API. + } + XPLMDataTypeID = ( + { Data of a type the current XPLM doesn't do. } + xplmType_Unknown = 0 + + { A single 4-byte integer, native endian. } + ,xplmType_Int = 1 + + { A single 4-byte float, native endian. } + ,xplmType_Float = 2 + + { A single 8-byte double, native endian. } + ,xplmType_Double = 4 + + { An array of 4-byte floats, native endian. } + ,xplmType_FloatArray = 8 + + { An array of 4-byte integers, native endian. } + ,xplmType_IntArray = 16 + + { A variable block of data. } + ,xplmType_Data = 32 + + ); + PXPLMDataTypeID = ^XPLMDataTypeID; + + { + XPLMFindDataRef + + Given a c-style string that names the data ref, this routine looks up the + actual opaque XPLMDataRef that you use to read and write the data. The + string names for datarefs are published on the X-Plane SDK web site. + + This function returns NULL if the data ref cannot be found. + + NOTE: this function is relatively expensive; save the XPLMDataRef this + function returns for future use. Do not look up your data ref by string + every time you need to read or write it. + } + FUNCTION XPLMFindDataRef( + inDataRefName : XPLMString) : XPLMDataRef; + cdecl; external XPLM_DLL; + + { + XPLMCanWriteDataRef + + Given a data ref, this routine returns true if you can successfully set the + data, false otherwise. Some datarefs are read-only. + + NOTE: even if a dataref is marked writable, it may not act writable. This + can happen for datarefs that X-Plane writes to on every frame of + simulation. In some cases, the dataref is writable but you have to set a + separate "override" dataref to 1 to stop X-Plane from writing it. + } + FUNCTION XPLMCanWriteDataRef( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMIsDataRefGood + + This function returns true if the passed in handle is a valid dataref that + is not orphaned. + + Note: there is normally no need to call this function; datarefs returned by + XPLMFindDataRef remain valid (but possibly orphaned) unless there is a + complete plugin reload (in which case your plugin is reloaded anyway). + Orphaned datarefs can be safely read and return 0. Therefore you never need + to call XPLMIsDataRefGood to 'check' the safety of a dataref. + (XPLMIsDatarefGood performs some slow checking of the handle validity, so + it has a perormance cost.) + } + FUNCTION XPLMIsDataRefGood( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDataRefTypes + + This routine returns the types of the data ref for accessor use. If a data + ref is available in multiple data types, the bit-wise OR of these types + will be returned. + } + FUNCTION XPLMGetDataRefTypes( + inDataRef : XPLMDataRef) : XPLMDataTypeID; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * DATA ACCESSORS + ___________________________________________________________________________} +{ + These routines read and write the data references. For each supported data + type there is a reader and a writer. + + If the data ref is orphaned or the plugin that provides it is disabled or + there is a type mismatch, the functions that read data will return 0 as a + default value or not modify the passed in memory. The plugins that write + data will not write under these circumstances or if the data ref is + read-only. + + NOTE: to keep the overhead of reading datarefs low, these routines do not + do full validation of a dataref; passing a junk value for a dataref can + result in crashing the sim. The get/set APIs do check for NULL. + + For array-style datarefs, you specify the number of items to read/write and + the offset into the array; the actual number of items read or written is + returned. This may be less to prevent an array-out-of-bounds error. +} + + + { + XPLMGetDatai + + Read an integer data ref and return its value. The return value is the + dataref value or 0 if the dataref is NULL or the plugin is disabled. + } + FUNCTION XPLMGetDatai( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatai + + Write a new value to an integer data ref. This routine is a no-op if the + plugin publishing the dataref is disabled, the dataref is NULL, or the + dataref is not writable. + } + PROCEDURE XPLMSetDatai( + inDataRef : XPLMDataRef; + inValue : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDataf + + Read a single precision floating point dataref and return its value. The + return value is the dataref value or 0.0 if the dataref is NULL or the + plugin is disabled. + } + FUNCTION XPLMGetDataf( + inDataRef : XPLMDataRef) : Single; + cdecl; external XPLM_DLL; + + { + XPLMSetDataf + + Write a new value to a single precision floating point data ref. This + routine is a no-op if the plugin publishing the dataref is disabled, the + dataref is NULL, or the dataref is not writable. + } + PROCEDURE XPLMSetDataf( + inDataRef : XPLMDataRef; + inValue : Single); + cdecl; external XPLM_DLL; + + { + XPLMGetDatad + + Read a double precision floating point dataref and return its value. The + return value is the dataref value or 0.0 if the dataref is NULL or the + plugin is disabled. + } + FUNCTION XPLMGetDatad( + inDataRef : XPLMDataRef) : Real; + cdecl; external XPLM_DLL; + + { + XPLMSetDatad + + Write a new value to a double precision floating point data ref. This + routine is a no-op if the plugin publishing the dataref is disabled, the + dataref is NULL, or the dataref is not writable. + } + PROCEDURE XPLMSetDatad( + inDataRef : XPLMDataRef; + inValue : Real); + cdecl; external XPLM_DLL; + + { + XPLMGetDatavi + + Read a part of an integer array dataref. If you pass NULL for outValues, + the routine will return the size of the array, ignoring inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatavi( + inDataRef : XPLMDataRef; + outValues : PInteger; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatavi + + Write part or all of an integer array dataref. The values passed by + inValues are written into the dataref starting at inOffset. Up to inCount + values are written; however if the values would write "off the end" of the + dataref array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatavi( + inDataRef : XPLMDataRef; + inValues : PInteger; + inoffset : Integer; + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDatavf + + Read a part of a single precision floating point array dataref. If you pass + NULL for outVaules, the routine will return the size of the array, ignoring + inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatavf( + inDataRef : XPLMDataRef; + outValues : PSingle; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatavf + + Write part or all of a single precision floating point array dataref. The + values passed by inValues are written into the dataref starting at + inOffset. Up to inCount values are written; however if the values would + write "off the end" of the dataref array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatavf( + inDataRef : XPLMDataRef; + inValues : PSingle; + inoffset : Integer; + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDatab + + Read a part of a byte array dataref. If you pass NULL for outVaules, the + routine will return the size of the array, ignoring inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatab( + inDataRef : XPLMDataRef; + outValue : pointer; { Can be nil } + inOffset : Integer; + inMaxBytes : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatab + + Write part or all of a byte array dataref. The values passed by inValues + are written into the dataref starting at inOffset. Up to inCount values are + written; however if the values would write "off the end" of the dataref + array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatab( + inDataRef : XPLMDataRef; + inValue : pointer; + inOffset : Integer; + inLength : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * PUBLISHING YOUR PLUGIN'S DATA + ___________________________________________________________________________} +{ + These functions allow you to create data references that other plug-ins and + X-Plane can access via the above data access APIs. Data references + published by other plugins operate the same as ones published by X-Plane in + all manners except that your data reference will not be available to other + plugins if/when your plugin is disabled. + + You share data by registering data provider callback functions. When a + plug-in requests your data, these callbacks are then called. You provide + one callback to return the value when a plugin 'reads' it and another to + change the value when a plugin 'writes' it. + + Important: you must pick a prefix for your datarefs other than "sim/" - + this prefix is reserved for X-Plane. The X-Plane SDK website contains a + registry where authors can select a unique first word for dataref names, to + prevent dataref collisions between plugins. +} + + + { + XPLMGetDatai_f + + Data provider function pointers. + + These define the function pointers you provide to get or set data. Note + that you are passed a generic pointer for each one. This is the same + pointer you pass in your register routine; you can use it to locate plugin + variables, etc. + + The semantics of your callbacks are the same as the dataref accessor above + - basically routines like XPLMGetDatai are just pass-throughs from a caller + to your plugin. Be particularly mindful in implementing array dataref + read-write accessors; you are responsible for avoiding overruns, supporting + offset read/writes, and handling a read with a NULL buffer. + } +TYPE + XPLMGetDatai_f = FUNCTION( + inRefcon : pointer) : Integer; cdecl; + + { + XPLMSetDatai_f + } + XPLMSetDatai_f = PROCEDURE( + inRefcon : pointer; + inValue : Integer); cdecl; + + { + XPLMGetDataf_f + } + XPLMGetDataf_f = FUNCTION( + inRefcon : pointer) : Single; cdecl; + + { + XPLMSetDataf_f + } + XPLMSetDataf_f = PROCEDURE( + inRefcon : pointer; + inValue : Single); cdecl; + + { + XPLMGetDatad_f + } + XPLMGetDatad_f = FUNCTION( + inRefcon : pointer) : Real; cdecl; + + { + XPLMSetDatad_f + } + XPLMSetDatad_f = PROCEDURE( + inRefcon : pointer; + inValue : Real); cdecl; + + { + XPLMGetDatavi_f + } + XPLMGetDatavi_f = FUNCTION( + inRefcon : pointer; + outValues : PInteger; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; cdecl; + + { + XPLMSetDatavi_f + } + XPLMSetDatavi_f = PROCEDURE( + inRefcon : pointer; + inValues : PInteger; + inOffset : Integer; + inCount : Integer); cdecl; + + { + XPLMGetDatavf_f + } + XPLMGetDatavf_f = FUNCTION( + inRefcon : pointer; + outValues : PSingle; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; cdecl; + + { + XPLMSetDatavf_f + } + XPLMSetDatavf_f = PROCEDURE( + inRefcon : pointer; + inValues : PSingle; + inOffset : Integer; + inCount : Integer); cdecl; + + { + XPLMGetDatab_f + } + XPLMGetDatab_f = FUNCTION( + inRefcon : pointer; + outValue : pointer; { Can be nil } + inOffset : Integer; + inMaxLength : Integer) : Integer; cdecl; + + { + XPLMSetDatab_f + } + XPLMSetDatab_f = PROCEDURE( + inRefcon : pointer; + inValue : pointer; + inOffset : Integer; + inLength : Integer); cdecl; + + { + XPLMRegisterDataAccessor + + This routine creates a new item of data that can be read and written. Pass + in the data's full name for searching, the type(s) of the data for + accessing, and whether the data can be written to. For each data type you + support, pass in a read accessor function and a write accessor function if + necessary. Pass NULL for data types you do not support or write accessors + if you are read-only. + + You are returned a data ref for the new item of data created. You can use + this data ref to unregister your data later or read or write from it. + } + FUNCTION XPLMRegisterDataAccessor( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inIsWritable : Integer; + inReadInt : XPLMGetDatai_f; + inWriteInt : XPLMSetDatai_f; + inReadFloat : XPLMGetDataf_f; + inWriteFloat : XPLMSetDataf_f; + inReadDouble : XPLMGetDatad_f; + inWriteDouble : XPLMSetDatad_f; + inReadIntArray : XPLMGetDatavi_f; + inWriteIntArray : XPLMSetDatavi_f; + inReadFloatArray : XPLMGetDatavf_f; + inWriteFloatArray : XPLMSetDatavf_f; + inReadData : XPLMGetDatab_f; + inWriteData : XPLMSetDatab_f; + inReadRefcon : pointer; + inWriteRefcon : pointer) : XPLMDataRef; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterDataAccessor + + Use this routine to unregister any data accessors you may have registered. + You unregister a data ref by the XPLMDataRef you get back from + registration. Once you unregister a data ref, your function pointer will + not be called anymore. + } + PROCEDURE XPLMUnregisterDataAccessor( + inDataRef : XPLMDataRef); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * SHARING DATA BETWEEN MULTIPLE PLUGINS + ___________________________________________________________________________} +{ + The data reference registration APIs from the previous section allow a + plugin to publish data in a one-owner manner; the plugin that publishes the + data reference owns the real memory that the data ref uses. This is + satisfactory for most cases, but there are also cases where plugnis need to + share actual data. + + With a shared data reference, no one plugin owns the actual memory for the + data reference; the plugin SDK allocates that for you. When the first + plugin asks to 'share' the data, the memory is allocated. When the data is + changed, every plugin that is sharing the data is notified. + + Shared data references differ from the 'owned' data references from the + previous section in a few ways: + + * With shared data references, any plugin can create the data reference; + with owned plugins one plugin must create the data reference and others + subscribe. (This can be a problem if you don't know which set of plugins + will be present). + + * With shared data references, every plugin that is sharing the data is + notified when the data is changed. With owned data references, only the + one owner is notified when the data is changed. + + * With shared data references, you cannot access the physical memory of the + data reference; you must use the XPLMGet... and XPLMSet... APIs. With an + owned data reference, the one owning data reference can manipulate the + data reference's memory in any way it sees fit. + + Shared data references solve two problems: if you need to have a data + reference used by several plugins but do not know which plugins will be + installed, or if all plugins sharing data need to be notified when that + data is changed, use shared data references. +} + + + { + XPLMDataChanged_f + + An XPLMDataChanged_f is a callback that the XPLM calls whenever any other + plug-in modifies shared data. A refcon you provide is passed back to help + identify which data is being changed. In response, you may want to call one + of the XPLMGetDataxxx routines to find the new value of the data. + } +TYPE + XPLMDataChanged_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMShareData + + This routine connects a plug-in to shared data, creating the shared data if + necessary. inDataName is a standard path for the data ref, and inDataType + specifies the type. This function will create the data if it does not + exist. If the data already exists but the type does not match, an error is + returned, so it is important that plug-in authors collaborate to establish + public standards for shared data. + + If a notificationFunc is passed in and is not NULL, that notification + function will be called whenever the data is modified. The notification + refcon will be passed to it. This allows your plug-in to know which shared + data was changed if multiple shared data are handled by one callback, or if + the plug-in does not use global variables. + + A one is returned for successfully creating or finding the shared data; a + zero if the data already exists but is of the wrong type. + } + FUNCTION XPLMShareData( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inNotificationFunc : XPLMDataChanged_f; + inNotificationRefcon: pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnshareData + + This routine removes your notification function for shared data. Call it + when done with the data to stop receiving change notifications. Arguments + must match XPLMShareData. The actual memory will not necessarily be freed, + since other plug-ins could be using it. + } + FUNCTION XPLMUnshareData( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inNotificationFunc : XPLMDataChanged_f; + inNotificationRefcon: pointer) : Integer; + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDefs.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDefs.pas new file mode 100644 index 0000000..b614085 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDefs.pas @@ -0,0 +1,438 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDefs; +INTERFACE +{ + This file is contains the cross-platform and basic definitions for the + X-Plane SDK. + + The preprocessor macros APL and IBM must be defined to specify the + compilation target; define APL to 1 and IBM 0 to compile on Macintosh and + APL to 0 and IBM to 1 for Windows. You must specify these macro definitions + before including XPLMDefs.h or any other XPLM headers. You can do this + using the -D command line option or a preprocessor header. +} + + {$A4} +{$IFDEF LINUX} + {$DEFINE KYLIX} +{$ENDIF} +TYPE +{$IFNDEF DELPHI} +{$IFNDEF KYLIX} + Pchar = ^char; + Ppchar = ^Pchar; + Psingle = ^single; + Pinteger = ^integer; +{$ENDIF} +{$ENDIF} + Preal = ^real; + Plongint = ^longint; +{___________________________________________________________________________ + * DLL Definitions + ___________________________________________________________________________} +{ + These definitions control the importing and exporting of functions within + the DLL. + + You can prefix your five required callbacks with the PLUGIN_API macro to + declare them as exported C functions. The XPLM_API macro identifies + functions that are provided to you via the plugin SDK. (Link against + XPLM.lib to use these functions.) +} + + + +{___________________________________________________________________________ + * GLOBAL DEFINITIONS + ___________________________________________________________________________} +{ + These definitions are used in all parts of the SDK. +} + + +TYPE + { + XPLMPluginID + + Each plug-in is identified by a unique integer ID. This ID can be used to + disable or enable a plug-in, or discover what plug-in is 'running' at the + time. A plug-in ID is unique within the currently running instance of + X-Plane unless plug-ins are reloaded. Plug-ins may receive a different + unique ID each time they are loaded. This includes the unloading and + reloading of plugins that are part of the user's aircraft. + + For persistent identification of plug-ins, use XPLMFindPluginBySignature in + XPLMUtiltiies.h + + -1 indicates no plug-in. + } + XPLMPluginID = Integer; + PXPLMPluginID = ^XPLMPluginID; + +CONST + { No plugin. } + XPLM_NO_PLUGIN_ID = (-1); + + { X-Plane itself } + XPLM_PLUGIN_XPLANE = (0); + + { The current XPLM revision is 4.00 (400). } + kXPLM_Version = (400); + + { + XPLMKeyFlags + + These bitfields define modifier keys in a platform independent way. When a + key is pressed, a series of messages are sent to your plugin. The down + flag is set in the first of these messages, and the up flag in the last. + While the key is held down, messages are sent with neither to indicate that + the key is being held down as a repeated character. + + The control flag is mapped to the control flag on Macintosh and PC. + Generally X-Plane uses the control key and not the command key on + Macintosh, providing a consistent interface across platforms that does not + necessarily match the Macintosh user interface guidelines. There is not + yet a way for plugins to access the Macintosh control keys without using + #ifdefed code. + } +TYPE + XPLMKeyFlags = ( + { The shift key is down } + xplm_ShiftFlag = 1 + + { The option or alt key is down } + ,xplm_OptionAltFlag = 2 + + { The control key is down* } + ,xplm_ControlFlag = 4 + + { The key is being pressed down } + ,xplm_DownFlag = 8 + + { The key is being released } + ,xplm_UpFlag = 16 + + ); + PXPLMKeyFlags = ^XPLMKeyFlags; + +{___________________________________________________________________________ + * ASCII CONTROL KEY CODES + ___________________________________________________________________________} +{ + These definitions define how various control keys are mapped to ASCII key + codes. Not all key presses generate an ASCII value, so plugin code should + be prepared to see null characters come from the keyboard...this usually + represents a key stroke that has no equivalent ASCII, like a page-down + press. Use virtual key codes to find these key strokes. + + ASCII key codes take into account modifier keys; shift keys will affect + capitals and punctuation; control key combinations may have no vaild ASCII + and produce NULL. To detect control-key combinations, use virtual key + codes, not ASCII keys. +} + + +CONST + XPLM_KEY_RETURN = 13; + + XPLM_KEY_ESCAPE = 27; + + XPLM_KEY_TAB = 9; + + XPLM_KEY_DELETE = 8; + + XPLM_KEY_LEFT = 28; + + XPLM_KEY_RIGHT = 29; + + XPLM_KEY_UP = 30; + + XPLM_KEY_DOWN = 31; + + XPLM_KEY_0 = 48; + + XPLM_KEY_1 = 49; + + XPLM_KEY_2 = 50; + + XPLM_KEY_3 = 51; + + XPLM_KEY_4 = 52; + + XPLM_KEY_5 = 53; + + XPLM_KEY_6 = 54; + + XPLM_KEY_7 = 55; + + XPLM_KEY_8 = 56; + + XPLM_KEY_9 = 57; + + XPLM_KEY_DECIMAL = 46; + +{___________________________________________________________________________ + * VIRTUAL KEY CODES + ___________________________________________________________________________} +{ + These are cross-platform defines for every distinct keyboard press on the + computer. Every physical key on the keyboard has a virtual key code. So + the "two" key on the top row of the main keyboard has a different code from + the "two" key on the numeric key pad. But the 'w' and 'W' character are + indistinguishable by virtual key code because they are the same physical + key (one with and one without the shift key). + + Use virtual key codes to detect keystrokes that do not have ASCII + equivalents, allow the user to map the numeric keypad separately from the + main keyboard, and detect control key and other modifier-key combinations + that generate ASCII control key sequences (many of which are not available + directly via character keys in the SDK). + + To assign virtual key codes we started with the Microsoft set but made some + additions and changes. A few differences: + + 1. Modifier keys are not available as virtual key codes. You cannot get + distinct modifier press and release messages. Please do not try to use + modifier keys as regular keys; doing so will almost certainly interfere + with users' abilities to use the native X-Plane key bindings. + 2. Some keys that do not exist on both Mac and PC keyboards are removed. + 3. Do not assume that the values of these keystrokes are interchangeable + with MS v-keys. +} + + +CONST + XPLM_VK_BACK = $08; + + XPLM_VK_TAB = $09; + + XPLM_VK_CLEAR = $0C; + + XPLM_VK_RETURN = $0D; + + XPLM_VK_ESCAPE = $1B; + + XPLM_VK_SPACE = $20; + + XPLM_VK_PRIOR = $21; + + XPLM_VK_NEXT = $22; + + XPLM_VK_END = $23; + + XPLM_VK_HOME = $24; + + XPLM_VK_LEFT = $25; + + XPLM_VK_UP = $26; + + XPLM_VK_RIGHT = $27; + + XPLM_VK_DOWN = $28; + + XPLM_VK_SELECT = $29; + + XPLM_VK_PRINT = $2A; + + XPLM_VK_EXECUTE = $2B; + + XPLM_VK_SNAPSHOT = $2C; + + XPLM_VK_INSERT = $2D; + + XPLM_VK_DELETE = $2E; + + XPLM_VK_HELP = $2F; + + { XPLM_VK_0 thru XPLM_VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) } + XPLM_VK_0 = $30; + + XPLM_VK_1 = $31; + + XPLM_VK_2 = $32; + + XPLM_VK_3 = $33; + + XPLM_VK_4 = $34; + + XPLM_VK_5 = $35; + + XPLM_VK_6 = $36; + + XPLM_VK_7 = $37; + + XPLM_VK_8 = $38; + + XPLM_VK_9 = $39; + + { XPLM_VK_A thru XPLM_VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) } + XPLM_VK_A = $41; + + XPLM_VK_B = $42; + + XPLM_VK_C = $43; + + XPLM_VK_D = $44; + + XPLM_VK_E = $45; + + XPLM_VK_F = $46; + + XPLM_VK_G = $47; + + XPLM_VK_H = $48; + + XPLM_VK_I = $49; + + XPLM_VK_J = $4A; + + XPLM_VK_K = $4B; + + XPLM_VK_L = $4C; + + XPLM_VK_M = $4D; + + XPLM_VK_N = $4E; + + XPLM_VK_O = $4F; + + XPLM_VK_P = $50; + + XPLM_VK_Q = $51; + + XPLM_VK_R = $52; + + XPLM_VK_S = $53; + + XPLM_VK_T = $54; + + XPLM_VK_U = $55; + + XPLM_VK_V = $56; + + XPLM_VK_W = $57; + + XPLM_VK_X = $58; + + XPLM_VK_Y = $59; + + XPLM_VK_Z = $5A; + + XPLM_VK_NUMPAD0 = $60; + + XPLM_VK_NUMPAD1 = $61; + + XPLM_VK_NUMPAD2 = $62; + + XPLM_VK_NUMPAD3 = $63; + + XPLM_VK_NUMPAD4 = $64; + + XPLM_VK_NUMPAD5 = $65; + + XPLM_VK_NUMPAD6 = $66; + + XPLM_VK_NUMPAD7 = $67; + + XPLM_VK_NUMPAD8 = $68; + + XPLM_VK_NUMPAD9 = $69; + + XPLM_VK_MULTIPLY = $6A; + + XPLM_VK_ADD = $6B; + + XPLM_VK_SEPARATOR = $6C; + + XPLM_VK_SUBTRACT = $6D; + + XPLM_VK_DECIMAL = $6E; + + XPLM_VK_DIVIDE = $6F; + + XPLM_VK_F1 = $70; + + XPLM_VK_F2 = $71; + + XPLM_VK_F3 = $72; + + XPLM_VK_F4 = $73; + + XPLM_VK_F5 = $74; + + XPLM_VK_F6 = $75; + + XPLM_VK_F7 = $76; + + XPLM_VK_F8 = $77; + + XPLM_VK_F9 = $78; + + XPLM_VK_F10 = $79; + + XPLM_VK_F11 = $7A; + + XPLM_VK_F12 = $7B; + + XPLM_VK_F13 = $7C; + + XPLM_VK_F14 = $7D; + + XPLM_VK_F15 = $7E; + + XPLM_VK_F16 = $7F; + + XPLM_VK_F17 = $80; + + XPLM_VK_F18 = $81; + + XPLM_VK_F19 = $82; + + XPLM_VK_F20 = $83; + + XPLM_VK_F21 = $84; + + XPLM_VK_F22 = $85; + + XPLM_VK_F23 = $86; + + XPLM_VK_F24 = $87; + + { The following definitions are extended and are not based on the Microsoft } + { key set. } + XPLM_VK_EQUAL = $B0; + + XPLM_VK_MINUS = $B1; + + XPLM_VK_RBRACE = $B2; + + XPLM_VK_LBRACE = $B3; + + XPLM_VK_QUOTE = $B4; + + XPLM_VK_SEMICOLON = $B5; + + XPLM_VK_BACKSLASH = $B6; + + XPLM_VK_COMMA = $B7; + + XPLM_VK_SLASH = $B8; + + XPLM_VK_PERIOD = $B9; + + XPLM_VK_BACKQUOTE = $BA; + + XPLM_VK_ENTER = $BB; + + XPLM_VK_NUMPAD_ENT = $BC; + + XPLM_VK_NUMPAD_EQ = $BD; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDisplay.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDisplay.pas new file mode 100644 index 0000000..ee4242c --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMDisplay.pas @@ -0,0 +1,1630 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDisplay; +INTERFACE +{ + This API provides the basic hooks to draw in X-Plane and create user + interface. All X-Plane drawing is done in OpenGL. The X-Plane plug-in + manager takes care of properly setting up the OpenGL context and matrices. + You do not decide when in your code's execution to draw; X-Plane tells you + (via callbacks) when it is ready to have your plugin draw. + + X-Plane's drawing strategy is straightforward: every "frame" the screen is + rendered by drawing the 3-D scene (dome, ground, objects, airplanes, etc.) + and then drawing the cockpit on top of it. Alpha blending is used to + overlay the cockpit over the world (and the gauges over the panel, etc.). + X-Plane user interface elements (including windows like the map, the main + menu, etc.) are then drawn on top of the cockpit. + + There are two ways you can draw: directly and in a window. + + Direct drawing (deprecated!---more on that below) involves drawing to the + screen before or after X-Plane finishes a phase of drawing. When you draw + directly, you can specify whether X-Plane is to complete this phase or not. + This allows you to do three things: draw before X-Plane does (under it), + draw after X-Plane does (over it), or draw instead of X-Plane. + + To draw directly, you register a callback and specify which phase you want + to intercept. The plug-in manager will call you over and over to draw that + phase. + + Direct drawing allows you to override scenery, panels, or anything. Note + that you cannot assume that you are the only plug-in drawing at this phase. + + Direct drawing is deprecated; at some point in the X-Plane 11 run, it will + likely become unsupported entirely as X-Plane transitions from OpenGL to + modern graphics API backends (e.g., Vulkan, Metal, etc.). In the long term, + plugins should use the XPLMInstance API for drawing 3-D objects---this will + be much more efficient than general 3-D OpenGL drawing, and it will + actually be supported by the new graphics backends. We do not yet know what + the post-transition API for generic 3-D drawing will look like (if it + exists at all). + + In contrast to direct drawing, window drawing provides a higher level + functionality. With window drawing, you create a 2-D window that takes up a + portion of the screen. Window drawing is always two dimensional. Window + drawing is front-to-back controlled; you can specify that you want your + window to be brought on top, and other plug-ins may put their window on top + of you. Window drawing also allows you to sign up for key presses and + receive mouse clicks. + + Drawing into the screen of an avionics device, like a GPS or a Primary + Flight Display, is a way to extend or replace X-Plane's avionics. Most + screens can be displayed both in a 3d cockpit or + 2d panel, and also in separate popup windows. By installing drawing + callbacks for a certain avionics device, you can change or extend the + appearance of that device regardless whether it's installed in a 3d + cockpit or used in a separate display for home cockpits because you leave + the window managing to X-Plane. + + There are three ways to get keystrokes: + + 1. If you create a window, the window can take keyboard focus. It will + then receive all keystrokes. If no window has focus, X-Plane receives + keystrokes. Use this to implement typing in dialog boxes, etc. Only + one window may have focus at a time; your window will be notified if it + loses focus. + 2. If you need low level access to the keystroke stream, install a key + sniffer. Key sniffers can be installed above everything or right in + front of the sim. + 3. If you would like to associate key strokes with commands/functions in + your plug-in, you should simply register a command (via + XPLMCreateCommand()) and allow users to bind whatever key they choose to + that command. Another (now deprecated) method of doing so is to use a + hot key---a key-specific callback. Hotkeys are sent based on virtual + key strokes, so any key may be distinctly mapped with any modifiers. + Hot keys can be remapped by other plug-ins. As a plug-in, you don't + have to worry about what your hot key ends up mapped to; other plug-ins + may provide a UI for remapping keystrokes. So hotkeys allow a user to + resolve conflicts and customize keystrokes. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * DRAWING CALLBACKS + ___________________________________________________________________________} +{ + Basic drawing callbacks, for low level intercepting of X-Plane's render + loop. The purpose of drawing callbacks is to provide targeted additions or + replacements to X-Plane's graphics environment (for example, to add extra + custom objects, or replace drawing of the AI aircraft). Do not assume that + the drawing callbacks will be called in the order implied by the + enumerations. Also do not assume that each drawing phase ends before + another begins; they may be nested. + + Note that all APIs in this section are deprecated, and will likely be + removed during the X-Plane 11 run as part of the transition to + Vulkan/Metal/etc. See the XPLMInstance API for future-proof drawing of 3-D + objects. +} + + + { + XPLMDrawingPhase + + This constant indicates which part of drawing we are in. Drawing is done + from the back to the front. We get a callback before or after each item. + Metaphases provide access to the beginning and end of the 3d (scene) and + 2d (cockpit) drawing in a manner that is independent of new phases added + via X-Plane implementation. + + **NOTE**: As of XPLM302 the legacy 3D drawing phases (xplm_Phase_FirstScene + to xplm_Phase_LastScene) are deprecated. When running under X-Plane 11.50 + with the modern Vulkan or Metal backend, X-Plane will no longer call + these drawing phases. There is a new drawing phase, xplm_Phase_Modern3D, + which is supported under OpenGL and Vulkan which is called out roughly + where the old before xplm_Phase_Airplanes phase was for blending. This + phase is *NOT* supported under Metal and comes with potentially + substantial performance overhead. Please do *NOT* opt into this phase if + you don't do any actual drawing that requires the depth buffer in some + way! + + **WARNING**: As X-Plane's scenery evolves, some drawing phases may cease to + exist and new ones may be invented. If you need a particularly specific + use of these codes, consult Austin and/or be prepared to revise your code + as X-Plane evolves. + } +TYPE + XPLMDrawingPhase = ( +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. This is the earliest point at which you can draw } + { in 3-d. } + xplm_Phase_FirstScene = 0 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing of land and water. } + ,xplm_Phase_Terrain = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing runways and other airport detail. } + ,xplm_Phase_Airports = 10 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing roads, trails, trains, etc. } + ,xplm_Phase_Vectors = 15 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. 3-d objects (houses, smokestacks, etc. } + ,xplm_Phase_Objects = 20 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. External views of airplanes, both yours and the } + { AI aircraft. } + ,xplm_Phase_Airplanes = 25 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. This is the last point at which you can draw in } + { 3-d. } + ,xplm_Phase_LastScene = 30 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM302} + { A chance to do modern 3D drawing. } + ,xplm_Phase_Modern3D = 31 +{$ENDIF XPLM302} + + { This is the first phase where you can draw in 2-d. } + ,xplm_Phase_FirstCockpit = 35 + + { The non-moving parts of the aircraft panel. } + ,xplm_Phase_Panel = 40 + + { The moving parts of the aircraft panel. } + ,xplm_Phase_Gauges = 45 + + { Floating windows from plugins. } + ,xplm_Phase_Window = 50 + + { The last chance to draw in 2d. } + ,xplm_Phase_LastCockpit = 55 + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMap3D = 100 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMap2D = 101 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMapProfile = 102 +{$ENDIF XPLM200} + + ); + PXPLMDrawingPhase = ^XPLMDrawingPhase; + + { + XPLMDrawCallback_f + + This is the prototype for a low level drawing callback. You are passed in + the phase and whether it is before or after. If you are before the phase, + return 1 to let X-Plane draw or 0 to suppress X-Plane drawing. If you are + after the phase the return value is ignored. + + Refcon is a unique value that you specify when registering the callback, + allowing you to slip a pointer to your own data to the callback. + + Upon entry the OpenGL context will be correctly set up for you and OpenGL + will be in 'local' coordinates for 3d drawing and panel coordinates for 2d + drawing. The OpenGL state (texturing, etc.) will be unknown. + } + XPLMDrawCallback_f = FUNCTION( + inPhase : XPLMDrawingPhase; + inIsBefore : Integer; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMRegisterDrawCallback + + This routine registers a low level drawing callback. Pass in the phase you + want to be called for and whether you want to be called before or after. + This routine returns 1 if the registration was successful, or 0 if the + phase does not exist in this version of X-Plane. You may register a + callback multiple times for the same or different phases as long as the + refcon is unique each time. + + Note that this function will likely be removed during the X-Plane 11 run as + part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + future-proof drawing of 3-D objects. + } + FUNCTION XPLMRegisterDrawCallback( + inCallback : XPLMDrawCallback_f; + inPhase : XPLMDrawingPhase; + inWantsBefore : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterDrawCallback + + This routine unregisters a draw callback. You must unregister a callback + for each time you register a callback if you have registered it multiple + times with different refcons. The routine returns 1 if it can find the + callback to unregister, 0 otherwise. + + Note that this function will likely be removed during the X-Plane 11 run as + part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + future-proof drawing of 3-D objects. + } + FUNCTION XPLMUnregisterDrawCallback( + inCallback : XPLMDrawCallback_f; + inPhase : XPLMDrawingPhase; + inWantsBefore : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM400} +{___________________________________________________________________________ + * AVIONICS API + ___________________________________________________________________________} +{ + Drawing callbacks for before and after X-Plane draws the instrument screen + can be registered for every cockpit device. If the user plane does not + have the device installed, your callback will not be called! Use the + return value to enable or disable X-Plane's drawing. By drawing into the + framebuffer of the avionics device, your modifications will be visible + regardless whether the device's screen is in a 3d cockpit or a popup + window. +} + + + { + XPLMDeviceID + + This constant indicates the device we want to override or enhance. We can + get a callback before or after each item. + } +TYPE + XPLMDeviceID = ( + { GNS430, pilot side. } + xplm_device_GNS430_1 = 0 + + { GNS430, copilot side. } + ,xplm_device_GNS430_2 = 1 + + { GNS530, pilot side. } + ,xplm_device_GNS530_1 = 2 + + { GNS530, copilot side. } + ,xplm_device_GNS530_2 = 3 + + { generic airliner CDU, pilot side. } + ,xplm_device_CDU739_1 = 4 + + { generic airliner CDU, copilot side. } + ,xplm_device_CDU739_2 = 5 + + { G1000 Primary Flight Display, pilot side. } + ,xplm_device_G1000_PFD_1 = 6 + + { G1000 Multifunction Display. } + ,xplm_device_G1000_MFD = 7 + + { G1000 Primary Flight Display, copilot side. } + ,xplm_device_G1000_PFD_2 = 8 + + { Primus CDU, pilot side. } + ,xplm_device_CDU815_1 = 9 + + { Primus CDU, copilot side. } + ,xplm_device_CDU815_2 = 10 + + { Primus Primary Flight Display, pilot side. } + ,xplm_device_Primus_PFD_1 = 11 + + { Primus Primary Flight Display, copilot side. } + ,xplm_device_Primus_PFD_2 = 12 + + { Primus Multifunction Display, pilot side. } + ,xplm_device_Primus_MFD_1 = 13 + + { Primus Multifunction Display, copilot side. } + ,xplm_device_Primus_MFD_2 = 14 + + { Primus Multifunction Display, central. } + ,xplm_device_Primus_MFD_3 = 15 + + { Primus Radio Management Unit, pilot side. } + ,xplm_device_Primus_RMU_1 = 16 + + { Primus Radio Management Unit, copilot side. } + ,xplm_device_Primus_RMU_2 = 17 + + ); + PXPLMDeviceID = ^XPLMDeviceID; + + { + XPLMAvionicsCallback_f + + This is the prototype for your drawing callback. You are passed in the + device you are enhancing/replacing, and whether it is before or after + X-Plane drawing. If you are before X-Plane, return 1 to let X-Plane draw or + 0 to suppress X-Plane drawing. If you are after the phase the return value + is ignored. + + Refcon is a unique value that you specify when registering the callback, + allowing you to slip a pointer to your own data to the callback. + + Upon entry the OpenGL context will be correctly set up for you and OpenGL + will be in panel coordinates for 2d drawing. The OpenGL state (texturing, + etc.) will be unknown. + } + XPLMAvionicsCallback_f = FUNCTION( + inDeviceID : XPLMDeviceID; + inIsBefore : Integer; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMAvionicsID + + This is an opaque identifier for an avionics display that you enhance or + replace. When you register your callbacks (via + XPLMRegisterAvionicsCallbacksEx()), you will specify callbacks to handle + drawing, and get back such a handle. + } + XPLMAvionicsID = pointer; + PXPLMAvionicsID = ^XPLMAvionicsID; + + { + XPLMCustomizeAvionics_t + + The XPLMCustomizeAvionics_t structure defines all of the parameters used to + replace or enhance avionics for using XPLMRegisterAvionicsCallbacksEx(). + The structure will be expanded in future SDK APIs to include more features. + Always set the structSize member to the size of your struct in bytes! + } + XPLMCustomizeAvionics_t = RECORD + { Used to inform XPLMRegisterAvionicsCallbacksEx() of the SDK version you } + { compiled against; should always be set to sizeof(XPLMCustomizeAvionics_t) } + structSize : Integer; + { Which avionics device you want your drawing applied to. } + deviceId : XPLMDeviceID; + { The draw callback to be called before X-Plane draws. } + drawCallbackBefore : XPLMAvionicsCallback_f; + { The draw callback to be called after X-Plane has drawn. } + drawCallbackAfter : XPLMAvionicsCallback_f; + { A reference which will be passed into each of your draw callbacks. Use this} + { to pass information to yourself as needed. } + refcon : pointer; + END; + PXPLMCustomizeAvionics_t = ^XPLMCustomizeAvionics_t; + + { + XPLMRegisterAvionicsCallbacksEx + + This routine registers your callbacks for a device. This returns a handle. + If the returned handle is NULL, there was a problem interpreting your + input, most likely the struct size was wrong for your SDK version. If the + returned handle is not NULL, your callbacks will be called according to + schedule as long as your plugin is not deactivated, or unloaded, or your + call XPLMUnregisterAvionicsCallbacks(). + } + FUNCTION XPLMRegisterAvionicsCallbacksEx( + inParams : PXPLMCustomizeAvionics_t) : XPLMAvionicsID; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterAvionicsCallbacks + + This routine unregisters your callbacks for a device. They will no longer + be called. + } + PROCEDURE XPLMUnregisterAvionicsCallbacks( + inAvionicsId : XPLMAvionicsID); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM400} +{___________________________________________________________________________ + * WINDOW API + ___________________________________________________________________________} +{ + The window API provides a high-level abstraction for drawing with UI + interaction. + + Windows may operate in one of two modes: legacy (for plugins compiled + against old versions of the XPLM, as well as windows created via the + deprecated XPLMCreateWindow() function, rather than XPLMCreateWindowEx()), + or modern (for windows compiled against the XPLM300 or newer API, and + created via XPLMCreateWindowEx()). + + Modern windows have access to new X-Plane 11 windowing features, like + support for new positioning modes (including being "popped out" into their + own first-class window in the operating system). They can also optionally + be decorated in the style of X-Plane 11 windows (like the map). + + Modern windows operate in "boxel" units. A boxel ("box of pixels") is a + unit of virtual pixels which, depending on X-Plane's scaling, may + correspond to an arbitrary NxN "box" of real pixels on screen. Because + X-Plane handles this scaling automatically, you can effectively treat the + units as though you were simply drawing in pixels, and know that when + X-Plane is running with 150% or 200% scaling, your drawing will be + automatically scaled (and likewise all mouse coordinates, screen bounds, + etc. will also be auto-scaled). + + In contrast, legacy windows draw in true screen pixels, and thus tend to + look quite small when X-Plane is operating in a scaled mode. + + Legacy windows have their origin in the lower left of the main X-Plane + window. In contrast, since modern windows are not constrained to the main + window, they have their origin in the lower left of the entire global + desktop space, and the lower left of the main X-Plane window is not + guaranteed to be (0, 0). In both cases, x increases as you move left, and y + increases as you move up. +} + + +TYPE + { + XPLMWindowID + + This is an opaque identifier for a window. You use it to control your + window. When you create a window (via either XPLMCreateWindow() or + XPLMCreateWindowEx()), you will specify callbacks to handle drawing, mouse + interaction, etc. + } + XPLMWindowID = pointer; + PXPLMWindowID = ^XPLMWindowID; + + { + XPLMDrawWindow_f + + A callback to handle 2-D drawing of your window. You are passed in your + window and its refcon. Draw the window. You can use other XPLM functions + from this header to find the current dimensions of your window, etc. When + this callback is called, the OpenGL context will be set properly for 2-D + window drawing. + + **Note**: Because you are drawing your window over a background, you can + make a translucent window easily by simply not filling in your entire + window's bounds. + } + XPLMDrawWindow_f = PROCEDURE( + inWindowID : XPLMWindowID; + inRefcon : pointer); cdecl; + + { + XPLMHandleKey_f + + This function is called when a key is pressed or keyboard focus is taken + away from your window. If losingFocus is 1, you are losing the keyboard + focus, otherwise a key was pressed and inKey contains its character. + + The window ID passed in will be your window for key presses, or the other + window taking focus when losing focus. Note that in the modern plugin + system, often focus is taken by the window manager itself; for this resaon, + the window ID may be zero when losing focus, and you should not write code + that depends onit. + + The refcon passed in will be the one from registration, for both key + presses and losing focus. + + Warning: this API declares virtual keys as a signed character; however the + VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + to an unsigned char to get correct comparisons in C. + } + XPLMHandleKey_f = PROCEDURE( + inWindowID : XPLMWindowID; + inKey : XPLMChar; + inFlags : XPLMKeyFlags; + inVirtualKey : XPLMChar; + inRefcon : pointer; + losingFocus : Integer); cdecl; + + { + XPLMMouseStatus + + When the mouse is clicked, your mouse click routine is called repeatedly. + It is first called with the mouse down message. It is then called zero or + more times with the mouse-drag message, and finally it is called once with + the mouse up message. All of these messages will be directed to the same + window; you are guaranteed to not receive a drag or mouse-up event without + first receiving the corresponding mouse-down. + } + XPLMMouseStatus = ( + xplm_MouseDown = 1 + + ,xplm_MouseDrag = 2 + + ,xplm_MouseUp = 3 + + ); + PXPLMMouseStatus = ^XPLMMouseStatus; + + { + XPLMHandleMouseClick_f + + You receive this call for one of three events: + + - when the user clicks the mouse button down + - (optionally) when the user drags the mouse after a down-click, but before + the up-click + - when the user releases the down-clicked mouse button. + + You receive the x and y of the click, your window, and a refcon. Return 1 + to consume the click, or 0 to pass it through. + + WARNING: passing clicks through windows (as of this writing) causes mouse + tracking problems in X-Plane; do not use this feature! + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleMouseClick_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + inMouse : XPLMMouseStatus; + inRefcon : pointer) : Integer; cdecl; + +{$IFDEF XPLM200} + { + XPLMCursorStatus + + XPLMCursorStatus describes how you would like X-Plane to manage the cursor. + See XPLMHandleCursor_f for more info. + } +TYPE + XPLMCursorStatus = ( + { X-Plane manages the cursor normally, plugin does not affect the cusrsor. } + xplm_CursorDefault = 0 + + { X-Plane hides the cursor. } + ,xplm_CursorHidden = 1 + + { X-Plane shows the cursor as the default arrow. } + ,xplm_CursorArrow = 2 + + { X-Plane shows the cursor but lets you select an OS cursor. } + ,xplm_CursorCustom = 3 + + ); + PXPLMCursorStatus = ^XPLMCursorStatus; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMHandleCursor_f + + The SDK calls your cursor status callback when the mouse is over your + plugin window. Return a cursor status code to indicate how you would like + X-Plane to manage the cursor. If you return xplm_CursorDefault, the SDK + will try lower-Z-order plugin windows, then let the sim manage the cursor. + + Note: you should never show or hide the cursor yourself---these APIs are + typically reference-counted and thus cannot safely and predictably be used + by the SDK. Instead return one of xplm_CursorHidden to hide the cursor or + xplm_CursorArrow/xplm_CursorCustom to show the cursor. + + If you want to implement a custom cursor by drawing a cursor in OpenGL, use + xplm_CursorHidden to hide the OS cursor and draw the cursor using a 2-d + drawing callback (after xplm_Phase_Window is probably a good choice, but + see deprecation warnings on the drawing APIs!). If you want to use a + custom OS-based cursor, use xplm_CursorCustom to ask X-Plane to show the + cursor but not affect its image. You can then use an OS specific call like + SetThemeCursor (Mac) or SetCursor/LoadCursor (Windows). + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleCursor_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + inRefcon : pointer) : XPLMCursorStatus; cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMHandleMouseWheel_f + + The SDK calls your mouse wheel callback when one of the mouse wheels is + scrolled within your window. Return 1 to consume the mouse wheel movement + or 0 to pass them on to a lower window. (If your window appears opaque to + the user, you should consume mouse wheel scrolling even if it does + nothing.) The number of "clicks" indicates how far the wheel was turned + since the last callback. The wheel is 0 for the vertical axis or 1 for the + horizontal axis (for OS/mouse combinations that support this). + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleMouseWheel_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + wheel : Integer; + clicks : Integer; + inRefcon : pointer) : Integer; cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM300} + { + XPLMWindowLayer + + XPLMWindowLayer describes where in the ordering of windows X-Plane should + place a particular window. Windows in higher layers cover windows in lower + layers. So, a given window might be at the top of its particular layer, but + it might still be obscured by a window in a higher layer. (This happens + frequently when floating windows, like X-Plane's map, are covered by a + modal alert.) + + Your window's layer can only be specified when you create the window (in + the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). For this reason, + layering only applies to windows created with new X-Plane 11 GUI features. + (Windows created using the older XPLMCreateWindow(), or windows compiled + against a pre-XPLM300 version of the SDK will simply be placed in the + flight overlay window layer.) + } +TYPE + XPLMWindowLayer = ( + { The lowest layer, used for HUD-like displays while flying. } + xplm_WindowLayerFlightOverlay = 0 + + { Windows that "float" over the sim, like the X-Plane 11 map does. If you are} + { not sure which layer to create your window in, choose floating. } + ,xplm_WindowLayerFloatingWindows = 1 + + { An interruptive modal that covers the sim with a transparent black overlay } + { to draw the user's focus to the alert } + ,xplm_WindowLayerModal = 2 + + { "Growl"-style notifications that are visible in a corner of the screen, } + { even over modals } + ,xplm_WindowLayerGrowlNotifications = 3 + + ); + PXPLMWindowLayer = ^XPLMWindowLayer; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMWindowDecoration + + XPLMWindowDecoration describes how "modern" windows will be displayed. This + impacts both how X-Plane draws your window as well as certain mouse + handlers. + + Your window's decoration can only be specified when you create the window + (in the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). + } +TYPE + XPLMWindowDecoration = ( + { X-Plane will draw no decoration for your window, and apply no automatic } + { click handlers. The window will not stop click from passing through its } + { bounds. This is suitable for "windows" which request, say, the full screen } + { bounds, then only draw in a small portion of the available area. } + xplm_WindowDecorationNone = 0 + + { The default decoration for "native" windows, like the map. Provides a solid} + { background, as well as click handlers for resizing and dragging the window.} + ,xplm_WindowDecorationRoundRectangle = 1 + + { X-Plane will draw no decoration for your window, nor will it provide resize} + { handlers for your window edges, but it will stop clicks from passing } + { through your windows bounds. } + ,xplm_WindowDecorationSelfDecorated = 2 + + { Like self-decorated, but with resizing; X-Plane will draw no decoration for} + { your window, but it will stop clicks from passing through your windows } + { bounds, and provide automatic mouse handlers for resizing. } + ,xplm_WindowDecorationSelfDecoratedResizable = 3 + + ); + PXPLMWindowDecoration = ^XPLMWindowDecoration; +{$ENDIF XPLM301} + +{$IFDEF XPLM200} + { + XPLMCreateWindow_t + + The XPMCreateWindow_t structure defines all of the parameters used to + create a modern window using XPLMCreateWindowEx(). The structure will be + expanded in future SDK APIs to include more features. Always set the + structSize member to the size of your struct in bytes! + + All windows created by this function in the XPLM300 version of the API are + created with the new X-Plane 11 GUI features. This means your plugin will + get to "know" about the existence of X-Plane windows other than the main + window. All drawing and mouse callbacks for your window will occur in + "boxels," giving your windows automatic support for high-DPI scaling in + X-Plane. In addition, your windows can opt-in to decoration with the + X-Plane 11 window styling, and you can use the + XPLMSetWindowPositioningMode() API to make your window "popped out" into a + first-class operating system window. + + Note that this requires dealing with your window's bounds in "global + desktop" positioning units, rather than the traditional panel coordinate + system. In global desktop coordinates, the main X-Plane window may not have + its origin at coordinate (0, 0), and your own window may have negative + coordinates. Assuming you don't implicitly assume (0, 0) as your origin, + the only API change you should need is to start using + XPLMGetMouseLocationGlobal() rather than XPLMGetMouseLocation(), and + XPLMGetScreenBoundsGlobal() instead of XPLMGetScreenSize(). + + If you ask to be decorated as a floating window, you'll get the blue window + control bar and blue backing that you see in X-Plane 11's normal "floating" + windows (like the map). + } +TYPE + XPLMCreateWindow_t = RECORD + { Used to inform XPLMCreateWindowEx() of the SDK version you compiled } + { against; should always be set to sizeof(XPLMCreateWindow_t) } + structSize : Integer; + { Left bound, in global desktop boxels } + left : Integer; + { Top bound, in global desktop boxels } + top : Integer; + { Right bound, in global desktop boxels } + right : Integer; + { Bottom bound, in global desktop boxels } + bottom : Integer; + visible : Integer; + drawWindowFunc : XPLMDrawWindow_f; + { A callback to handle the user left-clicking within your window (or NULL to } + { ignore left clicks) } + handleMouseClickFunc : XPLMHandleMouseClick_f; + handleKeyFunc : XPLMHandleKey_f; + handleCursorFunc : XPLMHandleCursor_f; + handleMouseWheelFunc : XPLMHandleMouseWheel_f; + { A reference which will be passed into each of your window callbacks. Use } + { this to pass information to yourself as needed. } + refcon : pointer; +{$IFDEF XPLM301} + { Specifies the type of X-Plane 11-style "wrapper" you want around your } + { window, if any } + decorateAsFloatingWindow : XPLMWindowDecoration; +{$ENDIF XPLM301} +{$IFDEF XPLM300} + layer : XPLMWindowLayer; +{$ENDIF XPLM300} +{$IFDEF XPLM300} + { A callback to handle the user right-clicking within your window (or NULL to} + { ignore right clicks) } + handleRightClickFunc : XPLMHandleMouseClick_f; +{$ENDIF XPLM300} + END; + PXPLMCreateWindow_t = ^XPLMCreateWindow_t; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMCreateWindowEx + + This routine creates a new "modern" window. You pass in an + XPLMCreateWindow_t structure with all of the fields set in. You must set + the structSize of the structure to the size of the actual structure you + used. Also, you must provide functions for every callback---you may not + leave them null! (If you do not support the cursor or mouse wheel, use + functions that return the default values.) + } + FUNCTION XPLMCreateWindowEx( + inParams : PXPLMCreateWindow_t) : XPLMWindowID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + { + XPLMCreateWindow + + Deprecated as of XPLM300. + + This routine creates a new legacy window. Unlike modern windows (created + via XPLMCreateWindowEx()), legacy windows do not have access to X-Plane 11 + features like automatic scaling for high-DPI screens, native window styles, + or support for being "popped out" into first-class operating system + windows. + + Pass in the dimensions and offsets to the window's bottom left corner from + the bottom left of the screen. You can specify whether the window is + initially visible or not. Also, you pass in three callbacks to run the + window and a refcon. This function returns a window ID you can use to + refer to the new window. + + NOTE: Legacy windows do not have "frames"; you are responsible for drawing + the background and frame of the window. Higher level libraries have + routines which make this easy. + } + FUNCTION XPLMCreateWindow( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inIsVisible : Integer; + inDrawCallback : XPLMDrawWindow_f; + inKeyCallback : XPLMHandleKey_f; + inMouseCallback : XPLMHandleMouseClick_f; + inRefcon : pointer) : XPLMWindowID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyWindow + + This routine destroys a window. The window's callbacks are not called + after this call. Keyboard focus is removed from the window before + destroying it. + } + PROCEDURE XPLMDestroyWindow( + inWindowID : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMGetScreenSize + + This routine returns the size of the main X-Plane OpenGL window in pixels. + This number can be used to get a rough idea of the amount of detail the + user will be able to see when drawing in 3-d. + } + PROCEDURE XPLMGetScreenSize( + outWidth : PInteger; { Can be nil } + outHeight : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetScreenBoundsGlobal + + This routine returns the bounds of the "global" X-Plane desktop, in boxels. + Unlike the non-global version XPLMGetScreenSize(), this is multi-monitor + aware. There are three primary consequences of multimonitor awareness. + + First, if the user is running X-Plane in full-screen on two or more + monitors (typically configured using one full-screen window per monitor), + the global desktop will be sized to include all X-Plane windows. + + Second, the origin of the screen coordinates is not guaranteed to be (0, + 0). Suppose the user has two displays side-by-side, both running at 1080p. + Suppose further that they've configured their OS to make the left display + their "primary" monitor, and that X-Plane is running in full-screen on + their right monitor only. In this case, the global desktop bounds would be + the rectangle from (1920, 0) to (3840, 1080). If the user later asked + X-Plane to draw on their primary monitor as well, the bounds would change + to (0, 0) to (3840, 1080). + + Finally, if the usable area of the virtual desktop is not a perfect + rectangle (for instance, because the monitors have different resolutions or + because one monitor is configured in the operating system to be above and + to the right of the other), the global desktop will include any wasted + space. Thus, if you have two 1080p monitors, and monitor 2 is configured to + have its bottom left touch monitor 1's upper right, your global desktop + area would be the rectangle from (0, 0) to (3840, 2160). + + Note that popped-out windows (windows drawn in their own operating system + windows, rather than "floating" within X-Plane) are not included in these + bounds. + } + PROCEDURE XPLMGetScreenBoundsGlobal( + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMReceiveMonitorBoundsGlobal_f + + This function is informed of the global bounds (in boxels) of a particular + monitor within the X-Plane global desktop space. Note that X-Plane must be + running in full screen on a monitor in order for that monitor to be passed + to you in this callback. + } +TYPE + XPLMReceiveMonitorBoundsGlobal_f = PROCEDURE( + inMonitorIndex : Integer; + inLeftBx : Integer; + inTopBx : Integer; + inRightBx : Integer; + inBottomBx : Integer; + inRefcon : pointer); cdecl; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMGetAllMonitorBoundsGlobal + + This routine immediately calls you back with the bounds (in boxels) of each + full-screen X-Plane window within the X-Plane global desktop space. Note + that if a monitor is *not* covered by an X-Plane window, you cannot get its + bounds this way. Likewise, monitors with only an X-Plane window (not in + full-screen mode) will not be included. + + If X-Plane is running in full-screen and your monitors are of the same size + and configured contiguously in the OS, then the combined global bounds of + all full-screen monitors will match the total global desktop bounds, as + returned by XPLMGetScreenBoundsGlobal(). (Of course, if X-Plane is running + in windowed mode, this will not be the case. Likewise, if you have + differently sized monitors, the global desktop space will include wasted + space.) + + Note that this function's monitor indices match those provided by + XPLMGetAllMonitorBoundsOS(), but the coordinates are different (since the + X-Plane global desktop may not match the operating system's global desktop, + and one X-Plane boxel may be larger than one pixel due to 150% or 200% + scaling). + } + PROCEDURE XPLMGetAllMonitorBoundsGlobal( + inMonitorBoundsCallback: XPLMReceiveMonitorBoundsGlobal_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMReceiveMonitorBoundsOS_f + + This function is informed of the global bounds (in pixels) of a particular + monitor within the operating system's global desktop space. Note that a + monitor index being passed to you here does not indicate that X-Plane is + running in full screen on this monitor, or even that any X-Plane windows + exist on this monitor. + } +TYPE + XPLMReceiveMonitorBoundsOS_f = PROCEDURE( + inMonitorIndex : Integer; + inLeftPx : Integer; + inTopPx : Integer; + inRightPx : Integer; + inBottomPx : Integer; + inRefcon : pointer); cdecl; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMGetAllMonitorBoundsOS + + This routine immediately calls you back with the bounds (in pixels) of each + monitor within the operating system's global desktop space. Note that + unlike XPLMGetAllMonitorBoundsGlobal(), this may include monitors that have + no X-Plane window on them. + + Note that this function's monitor indices match those provided by + XPLMGetAllMonitorBoundsGlobal(), but the coordinates are different (since + the X-Plane global desktop may not match the operating system's global + desktop, and one X-Plane boxel may be larger than one pixel). + } + PROCEDURE XPLMGetAllMonitorBoundsOS( + inMonitorBoundsCallback: XPLMReceiveMonitorBoundsOS_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetMouseLocation + + Deprecated in XPLM300. Modern windows should use + XPLMGetMouseLocationGlobal() instead. + + This routine returns the current mouse location in pixels relative to the + main X-Plane window. The bottom left corner of the main window is (0, 0). + Pass NULL to not receive info about either parameter. + + Because this function gives the mouse position relative to the main X-Plane + window (rather than in global bounds), this function should only be used by + legacy windows. Modern windows should instead get the mouse position in + global desktop coordinates using XPLMGetMouseLocationGlobal(). + + Note that unlike XPLMGetMouseLocationGlobal(), if the mouse goes outside + the user's main monitor (for instance, to a pop out window or a secondary + monitor), this function will not reflect it. + } + PROCEDURE XPLMGetMouseLocation( + outX : PInteger; { Can be nil } + outY : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetMouseLocationGlobal + + Returns the current mouse location in global desktop boxels. Unlike + XPLMGetMouseLocation(), the bottom left of the main X-Plane window is not + guaranteed to be (0, 0)---instead, the origin is the lower left of the + entire global desktop space. In addition, this routine gives the real mouse + location when the mouse goes to X-Plane windows other than the primary + display. Thus, it can be used with both pop-out windows and secondary + monitors. + + This is the mouse location function to use with modern windows (i.e., those + created by XPLMCreateWindowEx()). + + Pass NULL to not receive info about either parameter. + } + PROCEDURE XPLMGetMouseLocationGlobal( + outX : PInteger; { Can be nil } + outY : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetWindowGeometry + + This routine returns the position and size of a window. The units and + coordinate system vary depending on the type of window you have. + + If this is a legacy window (one compiled against a pre-XPLM300 version of + the SDK, or an XPLM300 window that was not created using + XPLMCreateWindowEx()), the units are pixels relative to the main X-Plane + display. + + If, on the other hand, this is a new X-Plane 11-style window (compiled + against the XPLM300 SDK and created using XPLMCreateWindowEx()), the units + are global desktop boxels. + + Pass NULL to not receive any paramter. + } + PROCEDURE XPLMGetWindowGeometry( + inWindowID : XPLMWindowID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetWindowGeometry + + This routine allows you to set the position and size of a window. + + The units and coordinate system match those of XPLMGetWindowGeometry(). + That is, modern windows use global desktop boxel coordinates, while legacy + windows use pixels relative to the main X-Plane display. + + Note that this only applies to "floating" windows (that is, windows that + are drawn within the X-Plane simulation windows, rather than being "popped + out" into their own first-class operating system windows). To set the + position of windows whose positioning mode is xplm_WindowPopOut, you'll + need to instead use XPLMSetWindowGeometryOS(). + } + PROCEDURE XPLMSetWindowGeometry( + inWindowID : XPLMWindowID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetWindowGeometryOS + + This routine returns the position and size of a "popped out" window (i.e., + a window whose positioning mode is xplm_WindowPopOut), in operating system + pixels. Pass NULL to not receive any parameter. + } + PROCEDURE XPLMGetWindowGeometryOS( + inWindowID : XPLMWindowID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowGeometryOS + + This routine allows you to set the position and size, in operating system + pixel coordinates, of a popped out window (that is, a window whose + positioning mode is xplm_WindowPopOut, which exists outside the X-Plane + simulation window, in its own first-class operating system window). + + Note that you are responsible for ensuring both that your window is popped + out (using XPLMWindowIsPoppedOut()) and that a monitor really exists at the + OS coordinates you provide (using XPLMGetAllMonitorBoundsOS()). + } + PROCEDURE XPLMSetWindowGeometryOS( + inWindowID : XPLMWindowID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMGetWindowGeometryVR + + Returns the width and height, in boxels, of a window in VR. Note that you + are responsible for ensuring your window is in VR (using + XPLMWindowIsInVR()). + } + PROCEDURE XPLMGetWindowGeometryVR( + inWindowID : XPLMWindowID; + outWidthBoxels : PInteger; { Can be nil } + outHeightBoxels : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + +{$IFDEF XPLM301} + { + XPLMSetWindowGeometryVR + + This routine allows you to set the size, in boxels, of a window in VR (that + is, a window whose positioning mode is xplm_WindowVR). + + Note that you are responsible for ensuring your window is in VR (using + XPLMWindowIsInVR()). + } + PROCEDURE XPLMSetWindowGeometryVR( + inWindowID : XPLMWindowID; + widthBoxels : Integer; + heightBoxels : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + + { + XPLMGetWindowIsVisible + + Returns true (1) if the specified window is visible. + } + FUNCTION XPLMGetWindowIsVisible( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetWindowIsVisible + + This routine shows or hides a window. + } + PROCEDURE XPLMSetWindowIsVisible( + inWindowID : XPLMWindowID; + inIsVisible : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMWindowIsPoppedOut + + True if this window has been popped out (making it a first-class window in + the operating system), which in turn is true if and only if you have set + the window's positioning mode to xplm_WindowPopOut. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK cannot be popped out.) + } + FUNCTION XPLMWindowIsPoppedOut( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMWindowIsInVR + + True if this window has been moved to the virtual reality (VR) headset, + which in turn is true if and only if you have set the window's positioning + mode to xplm_WindowVR. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM301 version of + the SDK cannot be moved to VR.) + } + FUNCTION XPLMWindowIsInVR( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + +{$IFDEF XPLM300} + { + XPLMSetWindowGravity + + A window's "gravity" controls how the window shifts as the whole X-Plane + window resizes. A gravity of 1 means the window maintains its positioning + relative to the right or top edges, 0 the left/bottom, and 0.5 keeps it + centered. + + Default gravity is (0, 1, 0, 1), meaning your window will maintain its + position relative to the top left and will not change size as its + containing window grows. + + If you wanted, say, a window that sticks to the top of the screen (with a + constant height), but which grows to take the full width of the window, you + would pass (0, 1, 1, 1). Because your left and right edges would maintain + their positioning relative to their respective edges of the screen, the + whole width of your window would change with the X-Plane window. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will simply get the default gravity.) + } + PROCEDURE XPLMSetWindowGravity( + inWindowID : XPLMWindowID; + inLeftGravity : Single; + inTopGravity : Single; + inRightGravity : Single; + inBottomGravity : Single); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowResizingLimits + + Sets the minimum and maximum size of the client rectangle of the given + window. (That is, it does not include any window styling that you might + have asked X-Plane to apply on your behalf.) All resizing operations are + constrained to these sizes. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will have no minimum or maximum size.) + } + PROCEDURE XPLMSetWindowResizingLimits( + inWindowID : XPLMWindowID; + inMinWidthBoxels : Integer; + inMinHeightBoxels : Integer; + inMaxWidthBoxels : Integer; + inMaxHeightBoxels : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMWindowPositioningMode + + XPLMWindowPositionMode describes how X-Plane will position your window on + the user's screen. X-Plane will maintain this positioning mode even as the + user resizes their window or adds/removes full-screen monitors. + + Positioning mode can only be set for "modern" windows (that is, windows + created using XPLMCreateWindowEx() and compiled against the XPLM300 SDK). + Windows created using the deprecated XPLMCreateWindow(), or windows + compiled against a pre-XPLM300 version of the SDK will simply get the + "free" positioning mode. + } +TYPE + XPLMWindowPositioningMode = ( + { The default positioning mode. Set the window geometry and its future } + { position will be determined by its window gravity, resizing limits, and } + { user interactions. } + xplm_WindowPositionFree = 0 + + { Keep the window centered on the monitor you specify } + ,xplm_WindowCenterOnMonitor = 1 + + { Keep the window full screen on the monitor you specify } + ,xplm_WindowFullScreenOnMonitor = 2 + + { Like gui_window_full_screen_on_monitor, but stretches over *all* monitors } + { and popout windows. This is an obscure one... unless you have a very good } + { reason to need it, you probably don't! } + ,xplm_WindowFullScreenOnAllMonitors = 3 + + { A first-class window in the operating system, completely separate from the } + { X-Plane window(s) } + ,xplm_WindowPopOut = 4 + +{$IFDEF XPLM301} + { A floating window visible on the VR headset } + ,xplm_WindowVR = 5 +{$ENDIF XPLM301} + + ); + PXPLMWindowPositioningMode = ^XPLMWindowPositioningMode; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowPositioningMode + + Sets the policy for how X-Plane will position your window. + + Some positioning modes apply to a particular monitor. For those modes, you + can pass a negative monitor index to position the window on the main + X-Plane monitor (the screen with the X-Plane menu bar at the top). Or, if + you have a specific monitor you want to position your window on, you can + pass a real monitor index as received from, e.g., + XPLMGetAllMonitorBoundsOS(). + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will always use xplm_WindowPositionFree.) + } + PROCEDURE XPLMSetWindowPositioningMode( + inWindowID : XPLMWindowID; + inPositioningMode : XPLMWindowPositioningMode; + inMonitorIndex : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowTitle + + Sets the name for a window. This only applies to windows that opted-in to + styling as an X-Plane 11 floating window (i.e., with styling mode + xplm_WindowDecorationRoundRectangle) when they were created using + XPLMCreateWindowEx(). + } + PROCEDURE XPLMSetWindowTitle( + inWindowID : XPLMWindowID; + inWindowTitle : XPLMString); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetWindowRefCon + + Returns a window's reference constant, the unique value you can use for + your own purposes. + } + FUNCTION XPLMGetWindowRefCon( + inWindowID : XPLMWindowID) : pointer; + cdecl; external XPLM_DLL; + + { + XPLMSetWindowRefCon + + Sets a window's reference constant. Use this to pass data to yourself in + the callbacks. + } + PROCEDURE XPLMSetWindowRefCon( + inWindowID : XPLMWindowID; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMTakeKeyboardFocus + + This routine gives a specific window keyboard focus. Keystrokes will be + sent to that window. Pass a window ID of 0 to remove keyboard focus from + any plugin-created windows and instead pass keyboard strokes directly to + X-Plane. + } + PROCEDURE XPLMTakeKeyboardFocus( + inWindow : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMHasKeyboardFocus + + Returns true (1) if the indicated window has keyboard focus. Pass a window + ID of 0 to see if no plugin window has focus, and all keystrokes will go + directly to X-Plane. + } + FUNCTION XPLMHasKeyboardFocus( + inWindow : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMBringWindowToFront + + This routine brings the window to the front of the Z-order for its layer. + Windows are brought to the front automatically when they are created. + Beyond that, you should make sure you are front before handling mouse + clicks. + + Note that this only brings your window to the front of its layer + (XPLMWindowLayer). Thus, if you have a window in the floating window layer + (xplm_WindowLayerFloatingWindows), but there is a modal window (in layer + xplm_WindowLayerModal) above you, you would still not be the true frontmost + window after calling this. (After all, the window layers are strictly + ordered, and no window in a lower layer can ever be above any window in a + higher one.) + } + PROCEDURE XPLMBringWindowToFront( + inWindow : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMIsWindowInFront + + This routine returns true if the window you passed in is the frontmost + visible window in its layer (XPLMWindowLayer). + + Thus, if you have a window at the front of the floating window layer + (xplm_WindowLayerFloatingWindows), this will return true even if there is a + modal window (in layer xplm_WindowLayerModal) above you. (Not to worry, + though: in such a case, X-Plane will not pass clicks or keyboard input down + to your layer until the window above stops "eating" the input.) + + Note that legacy windows are always placed in layer + xplm_WindowLayerFlightOverlay, while modern-style windows default to + xplm_WindowLayerFloatingWindows. This means it's perfectly consistent to + have two different plugin-created windows (one legacy, one modern) *both* + be in the front (of their different layers!) at the same time. + } + FUNCTION XPLMIsWindowInFront( + inWindow : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * KEY SNIFFERS + ___________________________________________________________________________} +{ + Low-level keyboard handlers. Allows for intercepting keystrokes outside the + normal rules of the user interface. +} + + + { + XPLMKeySniffer_f + + This is the prototype for a low level key-sniffing function. Window-based + UI _should not use this_! The windowing system provides high-level + mediated keyboard access, via the callbacks you attach to your + XPLMCreateWindow_t. By comparison, the key sniffer provides low level + keyboard access. + + Key sniffers are provided to allow libraries to provide non-windowed user + interaction. For example, the MUI library uses a key sniffer to do pop-up + text entry. + + Return 1 to pass the key on to the next sniffer, the window manager, + X-Plane, or whomever is down stream. Return 0 to consume the key. + + Warning: this API declares virtual keys as a signed character; however the + VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + to an unsigned char to get correct comparisons in C. + } +TYPE + XPLMKeySniffer_f = FUNCTION( + inChar : XPLMChar; + inFlags : XPLMKeyFlags; + inVirtualKey : XPLMChar; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMRegisterKeySniffer + + This routine registers a key sniffing callback. You specify whether you + want to sniff before the window system, or only sniff keys the window + system does not consume. You should ALMOST ALWAYS sniff non-control keys + after the window system. When the window system consumes a key, it is + because the user has "focused" a window. Consuming the key or taking + action based on the key will produce very weird results. Returns + 1 if successful. + } + FUNCTION XPLMRegisterKeySniffer( + inCallback : XPLMKeySniffer_f; + inBeforeWindows : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterKeySniffer + + This routine unregisters a key sniffer. You must unregister a key sniffer + for every time you register one with the exact same signature. Returns 1 + if successful. + } + FUNCTION XPLMUnregisterKeySniffer( + inCallback : XPLMKeySniffer_f; + inBeforeWindows : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * HOT KEYS + ___________________________________________________________________________} +{ + Keystrokes that can be managed by others. These are lower-level than window + keyboard handlers (i.e., callbacks you attach to your XPLMCreateWindow_t), + but higher level than key sniffers. +} + + + { + XPLMHotKey_f + + Your hot key callback simply takes a pointer of your choosing. + } +TYPE + XPLMHotKey_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMHotKeyID + + An opaque ID used to identify a hot key. + } + XPLMHotKeyID = pointer; + PXPLMHotKeyID = ^XPLMHotKeyID; + + { + XPLMRegisterHotKey + + This routine registers a hot key. You specify your preferred key stroke + virtual key/flag combination, a description of what your callback does (so + other plug-ins can describe the plug-in to the user for remapping) and a + callback function and opaque pointer to pass in). A new hot key ID is + returned. During execution, the actual key associated with your hot key + may change, but you are insulated from this. + } + FUNCTION XPLMRegisterHotKey( + inVirtualKey : XPLMChar; + inFlags : XPLMKeyFlags; + inDescription : XPLMString; + inCallback : XPLMHotKey_f; + inRefcon : pointer) : XPLMHotKeyID; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterHotKey + + Unregisters a hot key. You can only unregister your own hot keys. + } + PROCEDURE XPLMUnregisterHotKey( + inHotKey : XPLMHotKeyID); + cdecl; external XPLM_DLL; + + { + XPLMCountHotKeys + + Returns the number of current hot keys. + } + FUNCTION XPLMCountHotKeys: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetNthHotKey + + Returns a hot key by index, for iteration on all hot keys. + } + FUNCTION XPLMGetNthHotKey( + inIndex : Integer) : XPLMHotKeyID; + cdecl; external XPLM_DLL; + + { + XPLMGetHotKeyInfo + + Returns information about the hot key. Return NULL for any parameter you + don't want info about. The description should be at least 512 chars long. + } + PROCEDURE XPLMGetHotKeyInfo( + inHotKey : XPLMHotKeyID; + outVirtualKey : XPLMString; { Can be nil } + outFlags : PXPLMKeyFlags; { Can be nil } + outDescription : XPLMString; { Can be nil } + outPlugin : PXPLMPluginID); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetHotKeyCombination + + Remaps a hot key's keystrokes. You may remap another plugin's keystrokes. + } + PROCEDURE XPLMSetHotKeyCombination( + inHotKey : XPLMHotKeyID; + inVirtualKey : XPLMChar; + inFlags : XPLMKeyFlags); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMGraphics.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMGraphics.pas new file mode 100644 index 0000000..20ff61a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMGraphics.pas @@ -0,0 +1,424 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMGraphics; +INTERFACE +{ + A few notes on coordinate systems: + + X-Plane uses three kinds of coordinates. Global coordinates are specified + as latitude, longitude and elevation. This coordinate system never changes + but is not very precise. + + OpenGL (or 'local') coordinates are cartesian and shift with the plane. + They offer more precision and are used for 3-d OpenGL drawing. The X axis + is aligned east-west with positive X meaning east. The Y axis is aligned + straight up and down at the point 0,0,0 (but since the earth is round it is + not truly straight up and down at other points). The Z axis is aligned + north-south at 0, 0, 0 with positive Z pointing south (but since the earth + is round it isn't exactly north-south as you move east or west of 0, 0, 0). + One unit is one meter and the point 0,0,0 is on the surface of the earth at + sea level for some latitude and longitude picked by the sim such that the + user's aircraft is reasonably nearby. + + 2-d Panel coordinates are 2d, with the X axis horizontal and the Y axis + vertical. The point 0,0 is the bottom left and 1024,768 is the upper + right of the screen. This is true no matter what resolution the user's + monitor is in; when running in higher resolution, graphics will be + scaled. + + Use X-Plane's routines to convert between global and local coordinates. Do + not attempt to do this conversion yourself; the precise 'roundness' of + X-Plane's physics model may not match your own, and (to make things + weirder) the user can potentially customize the physics of the current + planet. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * X-PLANE GRAPHICS + ___________________________________________________________________________} +{ + These routines allow you to use OpenGL with X-Plane. +} + + + { + XPLMTextureID + + XPLM Texture IDs name well-known textures in the sim for you to use. This + allows you to recycle textures from X-Plane, saving VRAM. + + *Warning*: do not use these enums. The only remaining use they have is to + access the legacy compatibility v10 UI texture; if you need this, get it + via the Widgets library. + } +TYPE + XPLMTextureID = ( + { The bitmap that contains window outlines, button outlines, fonts, etc. } + xplm_Tex_GeneralInterface = 0 + +{$IFDEF XPLM_DEPRECATED} + { The exterior paint for the user's aircraft (daytime). } + ,xplm_Tex_AircraftPaint = 1 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { The exterior light map for the user's aircraft. } + ,xplm_Tex_AircraftLiteMap = 2 +{$ENDIF XPLM_DEPRECATED} + + ); + PXPLMTextureID = ^XPLMTextureID; + + { + XPLMSetGraphicsState + + XPLMSetGraphicsState changes OpenGL's fixed function pipeline state. You + are not responsible for restoring any state that is accessed via + XPLMSetGraphicsState, but you are responsible for not accessing this state + directly. + + - inEnableFog - enables or disables fog, equivalent to: glEnable(GL_FOG); + - inNumberTexUnits - enables or disables a number of multitexturing units. + If the number is 0, 2d texturing is disabled entirely, as in + glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a + number of multitexturing units are enabled sequentially, starting with + unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB); glEnable + (GL_TEXTURE_2D); + - inEnableLighting - enables or disables OpenGL lighting, e.g. + glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + - inEnableAlphaTesting - enables or disables the alpha test per pixel, e.g. + glEnable(GL_ALPHA_TEST); + - inEnableAlphaBlending - enables or disables alpha blending per pixel, + e.g. glEnable(GL_BLEND); + - inEnableDepthTesting - enables per pixel depth testing, as in + glEnable(GL_DEPTH_TEST); + - inEnableDepthWriting - enables writing back of depth information to the + depth bufffer, as in glDepthMask(GL_TRUE); + + The purpose of this function is to change OpenGL state while keeping + X-Plane aware of the state changes; this keeps X-Plane from getting + surprised by OGL state changes, and prevents X-Plane and plug-ins from + having to set all state before all draws; XPLMSetGraphicsState internally + skips calls to change state that is already properly enabled. + + X-Plane does not have a 'default' OGL state for plug-ins with respect to + the above state vector; plug-ins should totally set OGL state using this + API before drawing. Use XPLMSetGraphicsState instead of any of the above + OpenGL calls. + + WARNING: Any routine that performs drawing (e.g. XPLMDrawString or widget + code) may change X-Plane's state. Always set state before drawing after + unknown code has executed. + + *Deprecation Warnings*: X-Plane's lighting and fog environemnt is + significantly more complex than the fixed function pipeline can express; + do not assume that lighting and fog state is a good approximation for 3-d + drawing. Prefer to use XPLMInstancing to draw objects. All calls to + XPLMSetGraphicsState should have no fog or lighting. + } + PROCEDURE XPLMSetGraphicsState( + inEnableFog : Integer; + inNumberTexUnits : Integer; + inEnableLighting : Integer; + inEnableAlphaTesting: Integer; + inEnableAlphaBlending: Integer; + inEnableDepthTesting: Integer; + inEnableDepthWriting: Integer); + cdecl; external XPLM_DLL; + + { + XPLMBindTexture2d + + XPLMBindTexture2d changes what texture is bound to the 2d texturing + target. This routine caches the current 2d texture across all texturing + units in the sim and plug-ins, preventing extraneous binding. For + example, consider several plug-ins running in series; if they all use the + 'general interface' bitmap to do UI, calling this function will skip the + rebinding of the general interface texture on all but the first plug-in, + which can provide better frame rate son some graphics cards. + + inTextureID is the ID of the texture object to bind; inTextureUnit is a + zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 + units. (This number may increase in future versions of X-Plane.) + + Use this routine instead of glBindTexture(GL_TEXTURE_2D, ....); + } + PROCEDURE XPLMBindTexture2d( + inTextureNum : Integer; + inTextureUnit : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGenerateTextureNumbers + + Use this routine instead of glGenTextures to generate new texture object + IDs. This routine historically ensured that plugins don't use texure IDs + that X-Plane is reserving for its own use. + } + PROCEDURE XPLMGenerateTextureNumbers( + outTextureIDs : PInteger; + inCount : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM_DEPRECATED} + { + XPLMGetTexture + + XPLMGetTexture returns the OpenGL texture ID of an X-Plane texture based on + a generic identifying code. For example, you can get the texture for + X-Plane's UI bitmaps. + } + FUNCTION XPLMGetTexture( + inTexture : XPLMTextureID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + { + XPLMWorldToLocal + + This routine translates coordinates from latitude, longitude, and altitude + to local scene coordinates. Latitude and longitude are in decimal degrees, + and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + meters in the local OpenGL coordinate system. + } + PROCEDURE XPLMWorldToLocal( + inLatitude : Real; + inLongitude : Real; + inAltitude : Real; + outX : PReal; + outY : PReal; + outZ : PReal); + cdecl; external XPLM_DLL; + + { + XPLMLocalToWorld + + This routine translates a local coordinate triplet back into latitude, + longitude, and altitude. Latitude and longitude are in decimal degrees, + and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + meters in the local OpenGL coordinate system. + + NOTE: world coordinates are less precise than local coordinates; you should + try to avoid round tripping from local to world and back. + } + PROCEDURE XPLMLocalToWorld( + inX : Real; + inY : Real; + inZ : Real; + outLatitude : PReal; + outLongitude : PReal; + outAltitude : PReal); + cdecl; external XPLM_DLL; + + { + XPLMDrawTranslucentDarkBox + + This routine draws a translucent dark box, partially obscuring parts of the + screen but making text easy to read. This is the same graphics primitive + used by X-Plane to show text files and ATC info. + } + PROCEDURE XPLMDrawTranslucentDarkBox( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * X-PLANE TEXT + ___________________________________________________________________________} + + { + XPLMFontID + + X-Plane features some fixed-character fonts. Each font may have its own + metrics. + + WARNING: Some of these fonts are no longer supported or may have changed + geometries. For maximum copmatibility, see the comments below. + + Note: X-Plane 7 supports proportional-spaced fonts. Since no measuring + routine is available yet, the SDK will normally draw using a fixed-width + font. You can use a dataref to enable proportional font drawing on XP7 if + you want to. + } +TYPE + XPLMFontID = ( + { Mono-spaced font for user interface. Available in all versions of the SDK.} + xplmFont_Basic = 0 + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Menus = 1 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Metal = 2 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Led = 3 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_LedWide = 4 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelHUD = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelEFIS = 6 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelGPS = 7 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosGA = 8 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosBC = 9 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosHM = 10 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosGANarrow = 11 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosBCNarrow = 12 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosHMNarrow = 13 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Timer = 14 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_FullRound = 15 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_SmallRound = 16 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Menus_Localized = 17 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM200} + { Proportional UI font. } + ,xplmFont_Proportional = 18 +{$ENDIF XPLM200} + + ); + PXPLMFontID = ^XPLMFontID; + + { + XPLMDrawString + + This routine draws a NULL termianted string in a given font. Pass in the + lower left pixel that the character is to be drawn onto. Also pass the + character and font ID. This function returns the x offset plus the width of + all drawn characters. The color to draw in is specified as a pointer to an + array of three floating point colors, representing RGB intensities from 0.0 + to 1.0. + } + PROCEDURE XPLMDrawString( + inColorRGB : PSingle; + inXOffset : Integer; + inYOffset : Integer; + inChar : XPLMString; + inWordWrapWidth : PInteger; { Can be nil } + inFontID : XPLMFontID); + cdecl; external XPLM_DLL; + + { + XPLMDrawNumber + + This routine draws a number similar to the digit editing fields in + PlaneMaker and data output display in X-Plane. Pass in a color, a + position, a floating point value, and formatting info. Specify how many + integer and how many decimal digits to show and whether to show a sign, as + well as a character set. This routine returns the xOffset plus width of the + string drawn. + } + PROCEDURE XPLMDrawNumber( + inColorRGB : PSingle; + inXOffset : Integer; + inYOffset : Integer; + inValue : Real; + inDigits : Integer; + inDecimals : Integer; + inShowSign : Integer; + inFontID : XPLMFontID); + cdecl; external XPLM_DLL; + + { + XPLMGetFontDimensions + + This routine returns the width and height of a character in a given font. + It also tells you if the font only supports numeric digits. Pass NULL if + you don't need a given field. Note that for a proportional font the width + will be an arbitrary, hopefully average width. + } + PROCEDURE XPLMGetFontDimensions( + inFontID : XPLMFontID; + outCharWidth : PInteger; { Can be nil } + outCharHeight : PInteger; { Can be nil } + outDigitsOnly : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMMeasureString + + This routine returns the width in pixels of a string using a given font. + The string is passed as a pointer plus length (and does not need to be null + terminated); this is used to allow for measuring substrings. The return + value is floating point; it is possible that future font drawing may allow + for fractional pixels. + } + FUNCTION XPLMMeasureString( + inFontID : XPLMFontID; + inChar : XPLMString; + inNumChars : Integer) : Single; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMInstance.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMInstance.pas new file mode 100644 index 0000000..a38d2bb --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMInstance.pas @@ -0,0 +1,125 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMInstance; +INTERFACE +{ + This API provides instanced drawing of X-Plane objects (.obj files). In + contrast to old drawing APIs, which required you to draw your own objects + per-frame, the instancing API allows you to simply register an OBJ for + drawing, then move or manipulate it later (as needed). + + This provides one tremendous benefit: it keeps all dataref operations for + your object in one place. Because datarefs are main thread only, allowing + dataref access anywhere is a serious performance bottleneck for the + simulator---the whole simulator has to pause and wait for each dataref + access. This performance penalty will only grow worse as X-Plane moves + toward an ever more heavily multithreaded engine. + + The instancing API allows X-Plane to isolate all dataref manipulations for + all plugin object drawing to one place, potentially providing huge + performance gains. + + Here's how it works: + + When an instance is created, it provides a list of all datarefs you want to + manipulate in for the OBJ in the future. This list of datarefs replaces the + ad-hoc collections of dataref objects previously used by art assets. Then, + per-frame, you can manipulate the instance by passing in a "block" of + packed floats representing the current values of the datarefs for your + instance. (Note that the ordering of this set of packed floats must exactly + match the ordering of the datarefs when you created your instance.) +} + +USES + XPLMDefs, XPLMScenery; + {$A4} +{___________________________________________________________________________ + * Instance Creation and Destruction + ___________________________________________________________________________} +{ + Registers and unregisters instances. +} + + +TYPE + { + XPLMInstanceRef + + An opaque handle to an instance. + } + XPLMInstanceRef = pointer; + PXPLMInstanceRef = ^XPLMInstanceRef; + + { + XPLMCreateInstance + + XPLMCreateInstance creates a new instance, managed by your plug-in, and + returns a handle to the instance. A few important requirements: + + * The object passed in must be fully loaded and returned from the XPLM + before you can create your instance; you cannot pass a null obj ref, nor + can you change the ref later. + + * If you use any custom datarefs in your object, they must be registered + before the object is loaded. This is true even if their data will be + provided via the instance dataref list. + + * The instance dataref array must be a valid ptr to an array of at least + one item that is null terminated. That is, if you do not want any + datarefs, you must passa ptr to an array with a null item. You cannot + pass null for this. + } + FUNCTION XPLMCreateInstance( + obj : XPLMObjectRef; + datarefs : PXPLMString) : XPLMInstanceRef; + cdecl; external XPLM_DLL; + + { + XPLMDestroyInstance + + XPLMDestroyInstance destroys and deallocates your instance; once called, + you are still responsible for releasing the OBJ ref. + + Tip: you can release your OBJ ref after you call XPLMCreateInstance as long + as you never use it again; the instance will maintain its own reference to + the OBJ and the object OBJ be deallocated when the instance is destroyed. + } + PROCEDURE XPLMDestroyInstance( + instance : XPLMInstanceRef); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * Instance Manipulation + ___________________________________________________________________________} + + { + XPLMInstanceSetPosition + + Updates both the position of the instance and all datarefs you registered + for it. Call this from a flight loop callback or UI callback. + + __DO NOT__ call XPLMInstanceSetPosition from a drawing callback; the whole + point of instancing is that you do not need any drawing callbacks. Setting + instance data from a drawing callback may have undefined consequences, and + the drawing callback hurts FPS unnecessarily. + + The memory pointed to by the data pointer must be large enough to hold one + float for every data ref you have registered, and must contain valid + floating point data. + + BUG: before X-Plane 11.50, if you have no dataref registered, you must + still pass a valid pointer for data and not null. + } + PROCEDURE XPLMInstanceSetPosition( + instance : XPLMInstanceRef; + new_position : PXPLMDrawInfo_t; + data : PSingle); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMMap.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMMap.pas new file mode 100644 index 0000000..ea00ee0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMMap.pas @@ -0,0 +1,608 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMMap; +INTERFACE +{ + This API allows you to create new layers within X-Plane maps. Your layers + can draw arbitrary OpenGL, but they conveniently also have access to + X-Plane's built-in icon and label drawing functions. + + As of X-Plane 11, map drawing happens in three stages: + + 1. backgrounds and "fill," + 2. icons, and + 3. labels. + + Thus, all background drawing gets layered beneath all icons, which likewise + get layered beneath all labels. Within each stage, the map obeys a + consistent layer ordering, such that "fill" layers (layers that cover a + large amount of map area, like the terrain and clouds) appear beneath + "markings" layers (like airport icons). This ensures that layers with fine + details don't get obscured by layers with larger details. + + The XPLM map API reflects both aspects of this draw layering: you can + register a layer as providing either markings or fill, and X-Plane will + draw your fill layers beneath your markings layers (regardless of + registration order). Likewise, you are guaranteed that your layer's icons + (added from within an icon callback) will go above your layer's OpenGL + drawing, and your labels will go above your icons. + + The XPLM guarantees that all plugin-created fill layers go on top of all + native X-Plane fill layers, and all plugin-created markings layers go on + top of all X-Plane markings layers (with the exception of the aircraft + icons). It also guarantees that the draw order of your own plugin's layers + will be consistent. But, for layers created by different plugins, the only + guarantee is that we will draw all of one plugin's layers of each type + (fill, then markings), then all of the others'; we don't guarantee which + plugin's fill and markings layers go on top of the other's. + + As of X-Plane 11, maps use true cartographic projections for their drawing, + and different maps may use different projections. For that reason, all + drawing calls include an opaque handle for the projection you should use to + do the drawing. Any time you would draw at a particular latitude/longitude, + you'll need to ask the projection to translate that position into "map + coordinates." (Note that the projection is guaranteed not to change between + calls to your prepare-cache hook, so if you cache your map coordinates + ahead of time, there's no need to re-project them when you actually draw.) + + In addition to mapping normal latitude/longitude locations into map + coordinates, the projection APIs also let you know the current heading for + north. (Since X-Plane 11 maps can rotate to match the heading of the user's + aircraft, it's not safe to assume that north is at zero degrees rotation.) +} + +USES + XPLMDefs; + {$A4} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * DRAWING CALLBACKS + ___________________________________________________________________________} +{ + When you create a new map layer (using XPLMCreateMapLayer), you can provide + any or all of these callbacks. They allow you to insert your own OpenGL + drawing, text labels, and icons into the X-Plane map at the appropriate + places, allowing your layer to behave as similarly to X-Plane's built-in + layers as possible. +} + + +TYPE + { + XPLMMapLayerID + + This is an opaque handle for a plugin-created map layer. Pass it to the map + drawing APIs from an appropriate callback to draw in the layer you created. + } + XPLMMapLayerID = pointer; + PXPLMMapLayerID = ^XPLMMapLayerID; + + { + XPLMMapProjectionID + + This is an opaque handle for a map projection. Pass it to the projection + APIs to translate between map coordinates and latitude/longitudes. + } + XPLMMapProjectionID = pointer; + PXPLMMapProjectionID = ^XPLMMapProjectionID; + + { + XPLMMapStyle + + Indicates the visual style being drawn by the map. In X-Plane, the user can + choose between a number of map types, and different map types may have use + a different visual representation for the same elements (for instance, the + visual style of the terrain layer changes drastically between the VFR and + IFR layers), or certain layers may be disabled entirely in some map types + (e.g., localizers are only visible in the IFR low-enroute style). + } + XPLMMapStyle = ( + xplm_MapStyle_VFR_Sectional = 0 + + ,xplm_MapStyle_IFR_LowEnroute = 1 + + ,xplm_MapStyle_IFR_HighEnroute = 2 + + ); + PXPLMMapStyle = ^XPLMMapStyle; + + { + XPLMMapDrawingCallback_f + + This is the OpenGL map drawing callback for plugin-created map layers. You + can perform arbitrary OpenGL drawing from this callback, with one + exception: changes to the Z-buffer are not permitted, and will result in + map drawing errors. + + All drawing done from within this callback appears beneath all built-in + X-Plane icons and labels, but above the built-in "fill" layers (layers + providing major details, like terrain and water). Note, however, that the + relative ordering between the drawing callbacks of different plugins is not + guaranteed. + } + XPLMMapDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapIconDrawingCallback_f + + This is the icon drawing callback that enables plugin-created map layers to + draw icons using X-Plane's built-in icon drawing functionality. You can + request an arbitrary number of PNG icons to be drawn via + XPLMDrawMapIconFromSheet() from within this callback, but you may not + perform any OpenGL drawing here. + + Icons enqueued by this function will appear above all OpenGL drawing + (performed by your optional XPLMMapDrawingCallback_f), and above all + built-in X-Plane map icons of the same layer type ("fill" or "markings," as + determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + however, that the relative ordering between the drawing callbacks of + different plugins is not guaranteed. + } + XPLMMapIconDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapLabelDrawingCallback_f + + This is the label drawing callback that enables plugin-created map layers + to draw text labels using X-Plane's built-in labeling functionality. You + can request an arbitrary number of text labels to be drawn via + XPLMDrawMapLabel() from within this callback, but you may not perform any + OpenGL drawing here. + + Labels enqueued by this function will appear above all OpenGL drawing + (performed by your optional XPLMMapDrawingCallback_f), and above all + built-in map icons and labels of the same layer type ("fill" or "markings," + as determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + however, that the relative ordering between the drawing callbacks of + different plugins is not guaranteed. + } + XPLMMapLabelDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * LAYER MANAGEMENT CALLBACKS + ___________________________________________________________________________} +{ + These are various "bookkeeping" callbacks that your map layer can receive + (if you provide the callback in your XPLMCreateMapLayer_t). They allow you + to manage the lifecycle of your layer, as well as cache any + computationally-intensive preparation you might need for drawing. +} + + + { + XPLMMapPrepareCacheCallback_f + + A callback used to allow you to cache whatever information your layer needs + to draw in the current map area. + + This is called each time the map's total bounds change. This is typically + triggered by new DSFs being loaded, such that X-Plane discards old, + now-distant DSFs and pulls in new ones. At that point, the available bounds + of the map also change to match the new DSF area. + + By caching just the information you need to draw in this area, your future + draw calls can be made faster, since you'll be able to simply "splat" your + precomputed information each frame. + + We guarantee that the map projection will not change between successive + prepare cache calls, nor will any draw call give you bounds outside these + total map bounds. So, if you cache the projected map coordinates of all the + items you might want to draw in the total map area, you can be guaranteed + that no draw call will be asked to do any new work. + } +TYPE + XPLMMapPrepareCacheCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inTotalMapBoundsLeftTopRightBottom: PSingle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapWillBeDeletedCallback_f + + Called just before your map layer gets deleted. Because SDK-created map + layers have the same lifetime as the X-Plane map that contains them, if the + map gets unloaded from memory, your layer will too. + } + XPLMMapWillBeDeletedCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inRefcon : pointer); cdecl; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP LAYER CREATION AND DESTRUCTION + ___________________________________________________________________________} +{ + Enables the creation of new map layers. Layers are created for a particular + instance of the X-Plane map. For instance, if you want your layer to appear + in both the normal map interface and the Instructor Operator Station (IOS), + you would need two separate calls to XPLMCreateMapLayer(), with two + different values for your XPLMCreateMapLayer_t::layer_name. + + Your layer's lifetime will be determined by the lifetime of the map it is + created in. If the map is destroyed (on the X-Plane side), your layer will + be too, and you'll receive a callback to your + XPLMMapWillBeDeletedCallback_f. +} + + + { + XPLMMapLayerType + + Indicates the type of map layer you are creating. Fill layers will always + be drawn beneath markings layers. + } +TYPE + XPLMMapLayerType = ( + { A layer that draws "fill" graphics, like weather patterns, terrain, etc. } + { Fill layers frequently cover a large portion of the visible map area. } + xplm_MapLayer_Fill = 0 + + { A layer that provides markings for particular map features, like NAVAIDs, } + { airports, etc. Even dense markings layers cover a small portion of the } + { total map area. } + ,xplm_MapLayer_Markings = 1 + + ); + PXPLMMapLayerType = ^XPLMMapLayerType; + +CONST + { Globally unique identifier for X-Plane's Map window, used as the } + { mapToCreateLayerIn parameter in XPLMCreateMapLayer_t } + XPLM_MAP_USER_INTERFACE = "XPLM_MAP_USER_INTERFACE"; + + { Globally unique identifier for X-Plane's Instructor Operator Station } + { window, used as the mapToCreateLayerIn parameter in XPLMCreateMapLayer_t } + XPLM_MAP_IOS = "XPLM_MAP_IOS"; + + { + XPLMCreateMapLayer_t + + This structure defines all of the parameters used to create a map layer + using XPLMCreateMapLayer. The structure will be expanded in future SDK APIs + to include more features. Always set the structSize member to the size of + your struct in bytes! + + Each layer must be associated with exactly one map instance in X-Plane. + That map, and that map alone, will call your callbacks. Likewise, when that + map is deleted, your layer will be as well. + } +TYPE + XPLMCreateMapLayer_t = RECORD + { Used to inform XPLMCreateMapLayer() of the SDK version you compiled } + { against; should always be set to sizeof(XPLMCreateMapLayer_t) } + structSize : Integer; + { Globally unique string identifying the map you want this layer to appear } + { in. As of XPLM300, this is limited to one of XPLM_MAP_USER_INTERFACE or } + { XPLM_MAP_IOS } + mapToCreateLayerIn : XPLMString; + { The type of layer you are creating, used to determine draw order (all } + { plugin-created markings layers are drawn above all plugin-created fill } + { layers) } + layerType : XPLMMapLayerType; + { Optional callback to inform you this layer is being deleted (due to its } + { owning map being destroyed) } + willBeDeletedCallback : XPLMMapWillBeDeletedCallback_f; + { Optional callback you want to use to prepare your draw cache when the map } + { bounds change (set to NULL if you don't want this callback) } + prepCacheCallback : XPLMMapPrepareCacheCallback_f; + { Optional callback you want to use for arbitrary OpenGL drawing, which goes } + { beneath all icons in the map's layering system (set to NULL if you don't } + { want this callback) } + drawCallback : XPLMMapDrawingCallback_f; + { Optional callback you want to use for drawing icons, which go above all } + { built-in X-Plane icons (except the aircraft) in the map's layering system } + { (set to NULL if you don't want this callback) } + iconCallback : XPLMMapIconDrawingCallback_f; + { Optional callback you want to use for drawing map labels, which go above } + { all built-in X-Plane icons and labels (except those of aircraft) in the } + { map's layering system (set to NULL if you don't want this callback) } + labelCallback : XPLMMapLabelDrawingCallback_f; + { True if you want a checkbox to be created in the map UI to toggle this } + { layer on and off; false if the layer should simply always be enabled } + showUiToggle : Integer; + { Short label to use for this layer in the user interface } + layerName : XPLMString; + { A reference to arbitrary data that will be passed to your callbacks } + refcon : pointer; + END; + PXPLMCreateMapLayer_t = ^XPLMCreateMapLayer_t; + + { + XPLMCreateMapLayer + + This routine creates a new map layer. You pass in an XPLMCreateMapLayer_t + structure with all of the fields set in. You must set the structSize of + the structure to the size of the actual structure you used. + + Returns NULL if the layer creation failed. This happens most frequently + because the map you specified in your + XPLMCreateMapLayer_t::mapToCreateLayerIn field doesn't exist (that is, if + XPLMMapExists() returns 0 for the specified map). You can use + XPLMRegisterMapCreationHook() to get a notification each time a new map is + opened in X-Plane, at which time you can create layers in it. + } + FUNCTION XPLMCreateMapLayer( + inParams : PXPLMCreateMapLayer_t) : XPLMMapLayerID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyMapLayer + + Destroys a map layer you created (calling your + XPLMMapWillBeDeletedCallback_f if applicable). Returns true if a deletion + took place. + } + FUNCTION XPLMDestroyMapLayer( + inLayer : XPLMMapLayerID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMMapCreatedCallback_f + + A callback to notify your plugin that a new map has been created in + X-Plane. This is the best time to add a custom map layer using + XPLMCreateMapLayer(). + + No OpenGL drawing is permitted within this callback. + } +TYPE + XPLMMapCreatedCallback_f = PROCEDURE( + mapIdentifier : XPLMString; + refcon : pointer); cdecl; + + { + XPLMRegisterMapCreationHook + + Registers your callback to receive a notification each time a new map is + constructed in X-Plane. This callback is the best time to add your custom + map layer using XPLMCreateMapLayer(). + + Note that you will not be notified about any maps that already exist---you + can use XPLMMapExists() to check for maps that were created previously. + } + PROCEDURE XPLMRegisterMapCreationHook( + callback : XPLMMapCreatedCallback_f; + refcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMMapExists + + Returns 1 if the map with the specified identifier already exists in + X-Plane. In that case, you can safely call XPLMCreateMapLayer() specifying + that your layer should be added to that map. + } + FUNCTION XPLMMapExists( + mapIdentifier : XPLMString) : Integer; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP DRAWING + ___________________________________________________________________________} +{ + These APIs are only valid from within a map drawing callback (one of + XPLMIconDrawingCallback_t or XPLMMapLabelDrawingCallback_f). Your drawing + callbacks are registered when you create a new map layer as part of your + XPLMCreateMapLayer_t. The functions here hook into X-Plane's built-in map + drawing functionality for icons and labels, so that you get a consistent + style with the rest of the X-Plane map. + + Note that the X-Plane 11 map introduces a strict ordering: layers of type + xplm_MapLayer_Fill get drawn beneath all xplm_MapLayer_Markings layers. + Likewise, all OpenGL drawing (performed in your layer's + XPLMMapDrawingCallback_f) will appear beneath any icons and labels you + draw. +} + + + { + XPLMMapOrientation + + Indicates whether a map element should be match its rotation to the map + itself, or to the user interface. For instance, the map itself may be + rotated such that "up" matches the user's aircraft, but you may want to + draw a text label such that it is always rotated zero degrees relative to + the user's perspective. In that case, you would have it draw with UI + orientation. + } +TYPE + XPLMMapOrientation = ( + { Orient such that a 0 degree rotation matches the map's north } + xplm_MapOrientation_Map = 0 + + { Orient such that a 0 degree rotation is "up" relative to the user interface} + ,xplm_MapOrientation_UI = 1 + + ); + PXPLMMapOrientation = ^XPLMMapOrientation; + + { + XPLMDrawMapIconFromSheet + + Enables plugin-created map layers to draw PNG icons using X-Plane's + built-in icon drawing functionality. Only valid from within an + XPLMIconDrawingCallback_t (but you can request an arbitrary number of icons + to be drawn from within your callback). + + X-Plane will automatically manage the memory for your texture so that it + only has to be loaded from disk once as long as you continue drawing it + per-frame. (When you stop drawing it, the memory may purged in a "garbage + collection" pass, require a load from disk in the future.) + + Instead of having X-Plane draw a full PNG, this method allows you to use UV + coordinates to request a portion of the image to be drawn. This allows you + to use a single texture load (of an icon sheet, for example) to draw many + icons. Doing so is much more efficient than drawing a dozen different small + PNGs. + + The UV coordinates used here treat the texture you load as being comprised + of a number of identically sized "cells." You specify the width and height + in cells (ds and dt, respectively), as well as the coordinates within the + cell grid for the sub-image you'd like to draw. + + Note that you can use different ds and dt values in subsequent calls with + the same texture sheet. This enables you to use icons of different sizes in + the same sheet if you arrange them properly in the PNG. + + This function is only valid from within an XPLMIconDrawingCallback_t (but + you can request an arbitrary number of icons to be drawn from within your + callback). + } + PROCEDURE XPLMDrawMapIconFromSheet( + layer : XPLMMapLayerID; + inPngPath : XPLMString; + s : Integer; + t : Integer; + ds : Integer; + dt : Integer; + mapX : Single; + mapY : Single; + orientation : XPLMMapOrientation; + rotationDegrees : Single; + mapWidth : Single); + cdecl; external XPLM_DLL; + + { + XPLMDrawMapLabel + + Enables plugin-created map layers to draw text labels using X-Plane's + built-in labeling functionality. Only valid from within an + XPLMMapLabelDrawingCallback_f (but you can request an arbitrary number of + text labels to be drawn from within your callback). + } + PROCEDURE XPLMDrawMapLabel( + layer : XPLMMapLayerID; + inText : XPLMString; + mapX : Single; + mapY : Single; + orientation : XPLMMapOrientation; + rotationDegrees : Single); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP PROJECTIONS + ___________________________________________________________________________} +{ + As of X-Plane 11, the map draws using true cartographic projections, and + different maps may use different projections. Thus, to draw at a particular + latitude and longitude, you must first transform your real-world + coordinates into map coordinates. + + The map projection is also responsible for giving you the current scale of + the map. That is, the projection can tell you how many map units correspond + to 1 meter at a given point. + + Finally, the map projection can give you the current rotation of the map. + Since X-Plane 11 maps can rotate to match the heading of the aircraft, the + map's rotation can potentially change every frame. +} + + + { + XPLMMapProject + + Projects a latitude/longitude into map coordinates. This is the inverse of + XPLMMapUnproject(). + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + PROCEDURE XPLMMapProject( + projection : XPLMMapProjectionID; + latitude : Real; + longitude : Real; + outX : PSingle; + outY : PSingle); + cdecl; external XPLM_DLL; + + { + XPLMMapUnproject + + Transforms map coordinates back into a latitude and longitude. This is the + inverse of XPLMMapProject(). + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + PROCEDURE XPLMMapUnproject( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single; + outLatitude : PReal; + outLongitude : PReal); + cdecl; external XPLM_DLL; + + { + XPLMMapScaleMeter + + Returns the number of map units that correspond to a distance of one meter + at a given set of map coordinates. + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + FUNCTION XPLMMapScaleMeter( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single) : Single; + cdecl; external XPLM_DLL; + + { + XPLMMapGetNorthHeading + + Returns the heading (in degrees clockwise) from the positive Y axis in the + cartesian mapping coordinate system to true north at the point passed in. + You can use it as a clockwise rotational offset to align icons and other + 2-d drawing with true north on the map, compensating for rotations in the + map due to projection. + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + FUNCTION XPLMMapGetNorthHeading( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single) : Single; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMMenus.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMMenus.pas new file mode 100644 index 0000000..754a434 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMMenus.pas @@ -0,0 +1,277 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMMenus; +INTERFACE +{ + Plug-ins can create menus in the menu bar of X-Plane. This is done by + creating a menu and then creating items. Menus are referred to by an + opaque ID. Items are referred to by (zero-based) index number. + + Menus are "sandboxed" between plugins---no plugin can access the menus of + any other plugin. Furthermore, all menu indices are relative to your + plugin's menus only; if your plugin creates two sub-menus in the Plugins + menu at different times, it doesn't matter how many other plugins also + create sub-menus of Plugins in the intervening time: your sub-menus will be + given menu indices 0 and 1. (The SDK does some work in the back-end to + filter out menus that are irrelevant to your plugin in order to deliver + this consistency for each plugin.) + + When you create a menu item, you specify how we should handle clicks on + that menu item. You can either have the XPLM trigger a callback (the + XPLMMenuHandler_f associated with the menu that contains the item), or you + can simply have a command be triggered (with no associated call to your + menu handler). The advantage of the latter method is that X-Plane will + display any keyboard shortcuts associated with the command. (In contrast, + there are no keyboard shortcuts associated with menu handler callbacks with + specific parameters.) + + Menu text in X-Plane is UTF8; X-Plane's character set covers latin, greek + and cyrillic characters, Katakana, as well as some Japanese symbols. Some + APIs have a inDeprecatedAndIgnored parameter that used to select a + character set; since X-Plane 9 all localization is done via UTF-8 only. +} + +USES + XPLMDefs, XPLMUtilities; + {$A4} +{___________________________________________________________________________ + * XPLM MENUS + ___________________________________________________________________________} + + { + XPLMMenuCheck + + These enumerations define the various 'check' states for an X-Plane menu. + 'checking' in X-Plane actually appears as a light which may or may not be + lit. So there are three possible states. + } +TYPE + XPLMMenuCheck = ( + { there is no symbol to the left of the menu item. } + xplm_Menu_NoCheck = 0 + + { the menu has a mark next to it that is unmarked (not lit). } + ,xplm_Menu_Unchecked = 1 + + { the menu has a mark next to it that is checked (lit). } + ,xplm_Menu_Checked = 2 + + ); + PXPLMMenuCheck = ^XPLMMenuCheck; + + { + XPLMMenuID + + This is a unique ID for each menu you create. + } + XPLMMenuID = pointer; + PXPLMMenuID = ^XPLMMenuID; + + { + XPLMMenuHandler_f + + A menu handler function takes two reference pointers, one for the menu + (specified when the menu was created) and one for the item (specified when + the item was created). + } + XPLMMenuHandler_f = PROCEDURE( + inMenuRef : pointer; + inItemRef : pointer); cdecl; + + { + XPLMFindPluginsMenu + + This function returns the ID of the plug-ins menu, which is created for you + at startup. + } + FUNCTION XPLMFindPluginsMenu: XPLMMenuID; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMFindAircraftMenu + + This function returns the ID of the menu for the currently-loaded aircraft, + used for showing aircraft-specific commands. + + The aircraft menu is created by X-Plane at startup, but it remains hidden + until it is populated via XPLMAppendMenuItem() or + XPLMAppendMenuItemWithCommand(). + + Only plugins loaded with the user's current aircraft are allowed to access + the aircraft menu. For all other plugins, this will return NULL, and any + attempts to add menu items to it will fail. + } + FUNCTION XPLMFindAircraftMenu: XPLMMenuID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMCreateMenu + + This function creates a new menu and returns its ID. It returns NULL if + the menu cannot be created. Pass in a parent menu ID and an item index to + create a submenu, or NULL for the parent menu to put the menu in the menu + bar. The menu's name is only used if the menu is in the menubar. You also + pass a handler function and a menu reference value. Pass NULL for the + handler if you do not need callbacks from the menu (for example, if it only + contains submenus). + + Important: you must pass a valid, non-empty menu title even if the menu is + a submenu where the title is not visible. + } + FUNCTION XPLMCreateMenu( + inName : XPLMString; + inParentMenu : XPLMMenuID; + inParentItem : Integer; + inHandler : XPLMMenuHandler_f; + inMenuRef : pointer) : XPLMMenuID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyMenu + + This function destroys a menu that you have created. Use this to remove a + submenu if necessary. (Normally this function will not be necessary.) + } + PROCEDURE XPLMDestroyMenu( + inMenuID : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMClearAllMenuItems + + This function removes all menu items from a menu, allowing you to rebuild + it. Use this function if you need to change the number of items on a menu. + } + PROCEDURE XPLMClearAllMenuItems( + inMenuID : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMAppendMenuItem + + This routine appends a new menu item to the bottom of a menu and returns + its index. Pass in the menu to add the item to, the items name, and a void + * ref for this item. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + + Note that all menu indices returned are relative to your plugin's menus + only; if your plugin creates two sub-menus in the Plugins menu at different + times, it doesn't matter how many other plugins also create sub-menus of + Plugins in the intervening time: your sub-menus will be given menu indices + 0 and 1. (The SDK does some work in the back-end to filter out menus that + are irrelevant to your plugin in order to deliver this consistency for each + plugin.) + } + FUNCTION XPLMAppendMenuItem( + inMenu : XPLMMenuID; + inItemName : XPLMString; + inItemRef : pointer; + inDeprecatedAndIgnored: Integer) : Integer; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMAppendMenuItemWithCommand + + Like XPLMAppendMenuItem(), but instead of the new menu item triggering the + XPLMMenuHandler_f of the containiner menu, it will simply execute the + command you pass in. Using a command for your menu item allows the user to + bind a keyboard shortcut to the command and see that shortcut represented + in the menu. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + + Like XPLMAppendMenuItem(), all menu indices are relative to your plugin's + menus only. + } + FUNCTION XPLMAppendMenuItemWithCommand( + inMenu : XPLMMenuID; + inItemName : XPLMString; + inCommandToExecute : XPLMCommandRef) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMAppendMenuSeparator + + This routine adds a separator to the end of a menu. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + } + PROCEDURE XPLMAppendMenuSeparator( + inMenu : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMSetMenuItemName + + This routine changes the name of an existing menu item. Pass in the menu + ID and the index of the menu item. + } + PROCEDURE XPLMSetMenuItemName( + inMenu : XPLMMenuID; + inIndex : Integer; + inItemName : XPLMString; + inDeprecatedAndIgnored: Integer); + cdecl; external XPLM_DLL; + + { + XPLMCheckMenuItem + + Set whether a menu item is checked. Pass in the menu ID and item index. + } + PROCEDURE XPLMCheckMenuItem( + inMenu : XPLMMenuID; + index : Integer; + inCheck : XPLMMenuCheck); + cdecl; external XPLM_DLL; + + { + XPLMCheckMenuItemState + + This routine returns whether a menu item is checked or not. A menu item's + check mark may be on or off, or a menu may not have an icon at all. + } + PROCEDURE XPLMCheckMenuItemState( + inMenu : XPLMMenuID; + index : Integer; + outCheck : PXPLMMenuCheck); + cdecl; external XPLM_DLL; + + { + XPLMEnableMenuItem + + Sets whether this menu item is enabled. Items start out enabled. + } + PROCEDURE XPLMEnableMenuItem( + inMenu : XPLMMenuID; + index : Integer; + enabled : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM210} + { + XPLMRemoveMenuItem + + Removes one item from a menu. Note that all menu items below are moved up + one; your plugin must track the change in index numbers. + } + PROCEDURE XPLMRemoveMenuItem( + inMenu : XPLMMenuID; + inIndex : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMNavigation.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMNavigation.pas new file mode 100644 index 0000000..044b99b --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMNavigation.pas @@ -0,0 +1,350 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMNavigation; +INTERFACE +{ + The XPLM Navigation APIs give you some access to the navigation databases + inside X-Plane. X-Plane stores all navigation information in RAM, so by + using these APIs you can gain access to most information without having to + go to disk or parse the files yourself. + + You can also use this API to program the FMS. You must use the navigation + APIs to find the nav-aids you want to program into the FMS, since the FMS + is powered internally by X-Plane's navigation database. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * NAVIGATION DATABASE ACCESS + ___________________________________________________________________________} + + { + XPLMNavType + + These enumerations define the different types of navaids. They are each + defined with a separate bit so that they may be bit-wise added together to + form sets of nav-aid types. + + NOTE: xplm_Nav_LatLon is a specific lat-lon coordinate entered into the + FMS. It will not exist in the database, and cannot be programmed into the + FMS. Querying the FMS for navaids will return it. Use + XPLMSetFMSEntryLatLon to set a lat/lon waypoint. + } +TYPE + XPLMNavType = ( + xplm_Nav_Unknown = 0 + + ,xplm_Nav_Airport = 1 + + ,xplm_Nav_NDB = 2 + + ,xplm_Nav_VOR = 4 + + ,xplm_Nav_ILS = 8 + + ,xplm_Nav_Localizer = 16 + + ,xplm_Nav_GlideSlope = 32 + + ,xplm_Nav_OuterMarker = 64 + + ,xplm_Nav_MiddleMarker = 128 + + ,xplm_Nav_InnerMarker = 256 + + ,xplm_Nav_Fix = 512 + + ,xplm_Nav_DME = 1024 + + ,xplm_Nav_LatLon = 2048 + + ); + PXPLMNavType = ^XPLMNavType; + + { + XPLMNavRef + + XPLMNavRef is an iterator into the navigation database. The navigation + database is essentially an array, but it is not necessarily densely + populated. The only assumption you can safely make is that like-typed + nav-aids are grouped together. + + Use XPLMNavRef to refer to a nav-aid. + + XPLM_NAV_NOT_FOUND is returned by functions that return an XPLMNavRef when + the iterator must be invalid. + } + XPLMNavRef = Integer; + PXPLMNavRef = ^XPLMNavRef; + +CONST + XPLM_NAV_NOT_FOUND = -1; + + { + XPLMGetFirstNavAid + + This returns the very first navaid in the database. Use this to traverse + the entire database. Returns XPLM_NAV_NOT_FOUND if the nav database is + empty. + } + FUNCTION XPLMGetFirstNavAid: XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMGetNextNavAid + + Given a valid nav aid ref, this routine returns the next navaid. It + returns XPLM_NAV_NOT_FOUND if the nav aid passed in was invalid or if the + navaid passed in was the last one in the database. Use this routine to + iterate across all like-typed navaids or the entire database. + } + FUNCTION XPLMGetNextNavAid( + inNavAidRef : XPLMNavRef) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindFirstNavAidOfType + + This routine returns the ref of the first navaid of the given type in the + database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + database. You must pass exactly one nav aid type to this routine. + } + FUNCTION XPLMFindFirstNavAidOfType( + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindLastNavAidOfType + + This routine returns the ref of the last navaid of the given type in the + database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + database. You must pass exactly one nav aid type to this routine. + } + FUNCTION XPLMFindLastNavAidOfType( + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindNavAid + + This routine provides a number of searching capabilities for the nav + database. XPLMFindNavAid will search through every nav aid whose type is + within inType (multiple types may be added together) and return any + nav-aids found based on the following rules: + + * If inLat and inLon are not NULL, the navaid nearest to that lat/lon will + be returned, otherwise the last navaid found will be returned. + + * If inFrequency is not NULL, then any navaids considered must match this + frequency. Note that this will screen out radio beacons that do not have + frequency data published (like inner markers) but not fixes and airports. + + * If inNameFragment is not NULL, only navaids that contain the fragment in + their name will be returned. + + * If inIDFragment is not NULL, only navaids that contain the fragment in + their IDs will be returned. + + This routine provides a simple way to do a number of useful searches: + * Find the nearest navaid on this frequency. + * Find the nearest airport. + * Find the VOR whose ID is "KBOS". + * Find the nearest airport whose name contains "Chicago". + } + FUNCTION XPLMFindNavAid( + inNameFragment : XPLMString; { Can be nil } + inIDFragment : XPLMString; { Can be nil } + inLat : PSingle; { Can be nil } + inLon : PSingle; { Can be nil } + inFrequency : PInteger; { Can be nil } + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMGetNavAidInfo + + This routine returns information about a navaid. Any non-null field is + filled out with information if it is available. + + Frequencies are in the nav.dat convention as described in the X-Plane nav + database FAQ: NDB frequencies are exact, all others are multiplied by 100. + + The buffer for IDs should be at least 6 chars and the buffer for names + should be at least 41 chars, but since these values are likely to go up, I + recommend passing at least 32 chars for IDs and 256 chars for names when + possible. + + The outReg parameter tells if the navaid is within the local "region" of + loaded DSFs. (This information may not be particularly useful to plugins.) + The parameter is a single byte value 1 for true or 0 for false, not a C + string. + } + PROCEDURE XPLMGetNavAidInfo( + inRef : XPLMNavRef; + outType : PXPLMNavType; { Can be nil } + outLatitude : PSingle; { Can be nil } + outLongitude : PSingle; { Can be nil } + outHeight : PSingle; { Can be nil } + outFrequency : PInteger; { Can be nil } + outHeading : PSingle; { Can be nil } + outID : XPLMString; { Can be nil } + outName : XPLMString; { Can be nil } + outReg : XPLMString); { Can be nil } + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * FLIGHT MANAGEMENT COMPUTER + ___________________________________________________________________________} +{ + Note: the FMS works based on an array of entries. Indices into the array + are zero-based. Each entry is a nav-aid plus an altitude. The FMS tracks + the currently displayed entry and the entry that it is flying to. + + The FMS must be programmed with contiguous entries, so clearing an entry at + the end shortens the effective flight plan. There is a max of 100 + waypoints in the flight plan. +} + + + { + XPLMCountFMSEntries + + This routine returns the number of entries in the FMS. + } + FUNCTION XPLMCountFMSEntries: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDisplayedFMSEntry + + This routine returns the index of the entry the pilot is viewing. + } + FUNCTION XPLMGetDisplayedFMSEntry: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDestinationFMSEntry + + This routine returns the index of the entry the FMS is flying to. + } + FUNCTION XPLMGetDestinationFMSEntry: Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDisplayedFMSEntry + + This routine changes which entry the FMS is showing to the index specified. + } + PROCEDURE XPLMSetDisplayedFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetDestinationFMSEntry + + This routine changes which entry the FMS is flying the aircraft toward. + } + PROCEDURE XPLMSetDestinationFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetFMSEntryInfo + + This routine returns information about a given FMS entry. If the entry is + an airport or navaid, a reference to a nav entry can be returned allowing + you to find additional information (such as a frequency, ILS heading, name, + etc.). Note that this reference can be XPLM_NAV_NOT_FOUND until the + information has been looked up asynchronously, so after flightplan changes, + it might take up to a second for this field to become populated. The other + information is available immediately. For a lat/lon entry, the lat/lon is + returned by this routine but the navaid cannot be looked up (and the + reference will be XPLM_NAV_NOT_FOUND). FMS name entry buffers should be at + least 256 chars in length. + + WARNING: Due to a bug in X-Plane prior to 11.31, the navaid reference will + not be set to XPLM_NAV_NOT_FOUND while no data is available, and instead + just remain the value of the variable that you passed the pointer to. + Therefore, always initialize the variable to XPLM_NAV_NOT_FOUND before + passing the pointer to this function. + } + PROCEDURE XPLMGetFMSEntryInfo( + inIndex : Integer; + outType : PXPLMNavType; { Can be nil } + outID : XPLMString; { Can be nil } + outRef : PXPLMNavRef; { Can be nil } + outAltitude : PInteger; { Can be nil } + outLat : PSingle; { Can be nil } + outLon : PSingle); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetFMSEntryInfo + + This routine changes an entry in the FMS to have the destination navaid + passed in and the altitude specified. Use this only for airports, fixes, + and radio-beacon navaids. Currently of radio beacons, the FMS can only + support VORs and NDBs. Use the routines below to clear or fly to a lat/lon. + } + PROCEDURE XPLMSetFMSEntryInfo( + inIndex : Integer; + inRef : XPLMNavRef; + inAltitude : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetFMSEntryLatLon + + This routine changes the entry in the FMS to a lat/lon entry with the given + coordinates. + } + PROCEDURE XPLMSetFMSEntryLatLon( + inIndex : Integer; + inLat : Single; + inLon : Single; + inAltitude : Integer); + cdecl; external XPLM_DLL; + + { + XPLMClearFMSEntry + + This routine clears the given entry, potentially shortening the flight + plan. + } + PROCEDURE XPLMClearFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * GPS RECEIVER + ___________________________________________________________________________} +{ + These APIs let you read data from the GPS unit. +} + + { + XPLMGetGPSDestinationType + + This routine returns the type of the currently selected GPS destination, + one of fix, airport, VOR or NDB. + } + FUNCTION XPLMGetGPSDestinationType: XPLMNavType; + cdecl; external XPLM_DLL; + + { + XPLMGetGPSDestination + + This routine returns the current GPS destination. + } + FUNCTION XPLMGetGPSDestination: XPLMNavRef; + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMPlanes.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMPlanes.pas new file mode 100644 index 0000000..3801f0a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMPlanes.pas @@ -0,0 +1,278 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMPlanes; +INTERFACE +{ + The XPLMPlanes APIs allow you to control the various aircraft in X-Plane, + both the user's and the sim's. + + *Note*: unlike almost all other APIs in the SDK, aircraft paths are _full_ + file system paths for historical reasons. You'll need to prefix all + relative paths with the X-Plane path as accessed via XPLMGetSystemPath. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * USER AIRCRAFT ACCESS + ___________________________________________________________________________} + + { + XPLMSetUsersAircraft + + This routine changes the user's aircraft. Note that this will reinitialize + the user to be on the nearest airport's first runway. Pass in a full path + (hard drive and everything including the .acf extension) to the .acf file. + } + PROCEDURE XPLMSetUsersAircraft( + inAircraftPath : XPLMString); + cdecl; external XPLM_DLL; + { + XPLMPlaceUserAtAirport + + This routine places the user at a given airport. Specify the airport by + its X-Plane airport ID (e.g. 'KBOS'). + } + PROCEDURE XPLMPlaceUserAtAirport( + inAirportCode : XPLMString); + cdecl; external XPLM_DLL; +{$IFDEF XPLM300} + { + XPLMPlaceUserAtLocation + + Places the user at a specific location after performing any necessary + scenery loads. + + As with in-air starts initiated from the X-Plane user interface, the + aircraft will always start with its engines running, regardless of the + user's preferences (i.e., regardless of what the dataref + `sim/operation/prefs/startup_running` says). + } + PROCEDURE XPLMPlaceUserAtLocation( + latitudeDegrees : Real; + longitudeDegrees : Real; + elevationMetersMSL : Single; + headingDegreesTrue : Single; + speedMetersPerSecond: Single); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} +{___________________________________________________________________________ + * GLOBAL AIRCRAFT ACCESS + ___________________________________________________________________________} + +CONST + { The user's aircraft is always index 0. } + XPLM_USER_AIRCRAFT = 0; +{$IFDEF XPLM_DEPRECATED} + { + XPLMPlaneDrawState_t + + This structure contains additional plane parameter info to be passed to + draw plane. Make sure to fill in the size of the structure field with + sizeof(XPLMDrawPlaneState_t) so that the XPLM can tell how many fields you + knew about when compiling your plugin (since more fields may be added + later). + + Most of these fields are ratios from 0 to 1 for control input. X-Plane + calculates what the actual controls look like based on the .acf file for + that airplane. Note for the yoke inputs, this is what the pilot of the + plane has commanded (post artificial stability system if there were one) + and affects aelerons, rudder, etc. It is not necessarily related to the + actual position of the plane! + } +TYPE + XPLMPlaneDrawState_t = RECORD + { The size of the draw state struct. } + structSize : Integer; + { A ratio from [0..1] describing how far the landing gear is extended. } + gearPosition : Single; + { Ratio of flap deployment, 0 = up, 1 = full deploy. } + flapRatio : Single; + { Ratio of spoiler deployment, 0 = none, 1 = full deploy. } + spoilerRatio : Single; + { Ratio of speed brake deployment, 0 = none, 1 = full deploy. } + speedBrakeRatio : Single; + { Ratio of slat deployment, 0 = none, 1 = full deploy. } + slatRatio : Single; + { Wing sweep ratio, 0 = forward, 1 = swept. } + wingSweep : Single; + { Thrust power, 0 = none, 1 = full fwd, -1 = full reverse. } + thrust : Single; + { Total pitch input for this plane. } + yokePitch : Single; + { Total Heading input for this plane. } + yokeHeading : Single; + { Total Roll input for this plane. } + yokeRoll : Single; + END; + PXPLMPlaneDrawState_t = ^XPLMPlaneDrawState_t; +{$ENDIF XPLM_DEPRECATED} + { + XPLMCountAircraft + + This function returns the number of aircraft X-Plane is capable of having, + as well as the number of aircraft that are currently active. These numbers + count the user's aircraft. It can also return the plugin that is currently + controlling aircraft. In X-Plane 7, this routine reflects the number of + aircraft the user has enabled in the rendering options window. + } + PROCEDURE XPLMCountAircraft( + outTotalAircraft : PInteger; + outActiveAircraft : PInteger; + outController : PXPLMPluginID); + cdecl; external XPLM_DLL; + { + XPLMGetNthAircraftModel + + This function returns the aircraft model for the Nth aircraft. Indices are + zero based, with zero being the user's aircraft. The file name should be + at least 256 chars in length; the path should be at least 512 chars in + length. + } + PROCEDURE XPLMGetNthAircraftModel( + inIndex : Integer; + outFileName : XPLMString; + outPath : XPLMString); + cdecl; external XPLM_DLL; +{___________________________________________________________________________ + * EXCLUSIVE AIRCRAFT ACCESS + ___________________________________________________________________________} +{ + The following routines require exclusive access to the airplane APIs. Only + one plugin may have this access at a time. +} + + + { + XPLMPlanesAvailable_f + + Your airplanes available callback is called when another plugin gives up + access to the multiplayer planes. Use this to wait for access to + multiplayer. + } +TYPE + XPLMPlanesAvailable_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMAcquirePlanes + + XPLMAcquirePlanes grants your plugin exclusive access to the aircraft. It + returns 1 if you gain access, 0 if you do not. + + inAircraft - pass in an array of pointers to strings specifying the planes + you want loaded. For any plane index you do not want loaded, pass a + 0-length string. Other strings should be full paths with the .acf + extension. NULL terminates this array, or pass NULL if there are no planes + you want loaded. + + If you pass in a callback and do not receive access to the planes your + callback will be called when the airplanes are available. If you do receive + airplane access, your callback will not be called. + } + FUNCTION XPLMAcquirePlanes( + inAircraft : PXPLMString; { Can be nil } + inCallback : XPLMPlanesAvailable_f; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMReleasePlanes + + Call this function to release access to the planes. Note that if you are + disabled, access to planes is released for you and you must reacquire it. + } + PROCEDURE XPLMReleasePlanes; + cdecl; external XPLM_DLL; + + { + XPLMSetActiveAircraftCount + + This routine sets the number of active planes. If you pass in a number + higher than the total number of planes availables, only the total number of + planes available is actually used. + } + PROCEDURE XPLMSetActiveAircraftCount( + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetAircraftModel + + This routine loads an aircraft model. It may only be called if you have + exclusive access to the airplane APIs. Pass in the path of the model with + the .acf extension. The index is zero based, but you may not pass in 0 + (use XPLMSetUsersAircraft to load the user's aircracft). + } + PROCEDURE XPLMSetAircraftModel( + inIndex : Integer; + inAircraftPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMDisableAIForPlane + + This routine turns off X-Plane's AI for a given plane. The plane will + continue to draw and be a real plane in X-Plane, but will not move itself. + } + PROCEDURE XPLMDisableAIForPlane( + inPlaneIndex : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM_DEPRECATED} + { + XPLMDrawAircraft + + WARNING: Aircraft drawing via this API is deprecated and will not work in + future versions of X-Plane. Use XPLMInstance for 3-d drawing of custom + aircraft models. + + This routine draws an aircraft. It can only be called from a 3-d drawing + callback. Pass in the position of the plane in OpenGL local coordinates + and the orientation of the plane. A 1 for full drawing indicates that the + whole plane must be drawn; a 0 indicates you only need the nav lights + drawn. (This saves rendering time when planes are far away.) + } + PROCEDURE XPLMDrawAircraft( + inPlaneIndex : Integer; + inX : Single; + inY : Single; + inZ : Single; + inPitch : Single; + inRoll : Single; + inYaw : Single; + inFullDraw : Integer; + inDrawStateInfo : PXPLMPlaneDrawState_t); + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMReinitUsersPlane + + WARNING: DO NOT USE. Use XPLMPlaceUserAtAirport or + XPLMPlaceUserAtLocation. + + This function recomputes the derived flight model data from the aircraft + structure in memory. If you have used the data access layer to modify the + aircraft structure, use this routine to resynchronize X-Plane; since + X-Plane works at least partly from derived values, the sim will not behave + properly until this is called. + + WARNING: this routine does not necessarily place the airplane at the + airport; use XPLMSetUsersAircraft to be compatible. This routine is + provided to do special experimentation with flight models without resetting + flight. + } + PROCEDURE XPLMReinitUsersPlane; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMPlugin.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMPlugin.pas new file mode 100644 index 0000000..83fbb73 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMPlugin.pas @@ -0,0 +1,413 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMPlugin; +INTERFACE +{ + These APIs provide facilities to find and work with other plugins and + manage other plugins. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FINDING PLUGINS + ___________________________________________________________________________} +{ + These APIs allow you to find another plugin or yourself, or iterate across + all plugins. For example, if you wrote an FMS plugin that needed to talk + to an autopilot plugin, you could use these APIs to locate the autopilot + plugin. +} + + + { + XPLMGetMyID + + This routine returns the plugin ID of the calling plug-in. Call this to + get your own ID. + } + FUNCTION XPLMGetMyID: XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMCountPlugins + + This routine returns the total number of plug-ins that are loaded, both + disabled and enabled. + } + FUNCTION XPLMCountPlugins: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetNthPlugin + + This routine returns the ID of a plug-in by index. Index is 0 based from 0 + to XPLMCountPlugins-1, inclusive. Plugins may be returned in any arbitrary + order. + } + FUNCTION XPLMGetNthPlugin( + inIndex : Integer) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMFindPluginByPath + + This routine returns the plug-in ID of the plug-in whose file exists at the + passed in absolute file system path. XPLM_NO_PLUGIN_ID is returned if the + path does not point to a currently loaded plug-in. + } + FUNCTION XPLMFindPluginByPath( + inPath : XPLMString) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMFindPluginBySignature + + This routine returns the plug-in ID of the plug-in whose signature matches + what is passed in or XPLM_NO_PLUGIN_ID if no running plug-in has this + signature. Signatures are the best way to identify another plug-in as they + are independent of the file system path of a plug-in or the human-readable + plug-in name, and should be unique for all plug-ins. Use this routine to + locate another plugin that your plugin interoperates with + } + FUNCTION XPLMFindPluginBySignature( + inSignature : XPLMString) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMGetPluginInfo + + This routine returns information about a plug-in. Each parameter should be + a pointer to a buffer of at least + 256 characters, or NULL to not receive the information. + + outName - the human-readable name of the plug-in. outFilePath - the + absolute file path to the file that contains this plug-in. outSignature - a + unique string that identifies this plug-in. outDescription - a + human-readable description of this plug-in. + } + PROCEDURE XPLMGetPluginInfo( + inPlugin : XPLMPluginID; + outName : XPLMString; { Can be nil } + outFilePath : XPLMString; { Can be nil } + outSignature : XPLMString; { Can be nil } + outDescription : XPLMString); { Can be nil } + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * ENABLING/DISABLING PLUG-INS + ___________________________________________________________________________} +{ + These routines are used to work with plug-ins and manage them. Most + plugins will not need to use these APIs. +} + + + { + XPLMIsPluginEnabled + + Returns whether the specified plug-in is enabled for running. + } + FUNCTION XPLMIsPluginEnabled( + inPluginID : XPLMPluginID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMEnablePlugin + + This routine enables a plug-in if it is not already enabled. It returns 1 + if the plugin was enabled or successfully enables itself, 0 if it does not. + Plugins may fail to enable (for example, if resources cannot be acquired) + by returning 0 from their XPluginEnable callback. + } + FUNCTION XPLMEnablePlugin( + inPluginID : XPLMPluginID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMDisablePlugin + + This routine disableds an enabled plug-in. + } + PROCEDURE XPLMDisablePlugin( + inPluginID : XPLMPluginID); + cdecl; external XPLM_DLL; + + { + XPLMReloadPlugins + + This routine reloads all plug-ins. Once this routine is called and you + return from the callback you were within (e.g. a menu select callback) you + will receive your XPluginDisable and XPluginStop callbacks and your DLL + will be unloaded, then the start process happens as if the sim was starting + up. + } + PROCEDURE XPLMReloadPlugins; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * INTERPLUGIN MESSAGING + ___________________________________________________________________________} +{ + Plugin messages are defined as 32-bit integers. Messages below 0x00FFFFFF + are reserved for X-Plane and the plugin SDK. + + Messages come with a pointer parameter; the meaning of this pointer depends + on the message itself. In some messages, the pointer parameter contains an + actual typed pointer to data that can be inspected in the plugin; in these + cases the documentation will state that the parameter "points to" + information. + + in other cases, the value of the pointer is actually an integral number + stuffed into the pointer's storage. In these second cases, the pointer + parameter needs to be cast, not dereferenced. In these caess, the + documentation will state that the parameter "contains" a value, which will + always be an integral type. + + Some messages don't use the pointer parameter - in this case your plugin + should ignore it. + + Messages have two conceptual uses: notifications and commands. Commands + are sent from one plugin to another to induce behavior; notifications are + sent from one plugin to all others for informational purposes. It is + important that commands and notifications not have the same values because + this could cause a notification sent by one plugin to accidentally induce a + command in another. + + By convention, plugin-defined notifications should have the high bit set + (e.g. be greater or equal to unsigned 0x8000000) while commands should have + this bit be cleared. + + The following messages are sent to your plugin by X-Plane. +} + + +CONST + { This message is sent to your plugin whenever the user's plane crashes. The } + { parameter is ignored. } + XPLM_MSG_PLANE_CRASHED = 101; + + { This message is sent to your plugin whenever a new plane is loaded. The } + { parameter contains the index number of the plane being loaded; 0 indicates } + { the user's plane. } + XPLM_MSG_PLANE_LOADED = 102; + + { This messages is sent whenever the user's plane is positioned at a new } + { airport. The parameter is ignored. } + XPLM_MSG_AIRPORT_LOADED = 103; + + { This message is sent whenever new scenery is loaded. Use datarefs to } + { determine the new scenery files that were loaded. The parameter is ignored.} + XPLM_MSG_SCENERY_LOADED = 104; + + { This message is sent whenever the user adjusts the number of X-Plane } + { aircraft models. You must use XPLMCountPlanes to find out how many planes } + { are now available. This message will only be sent in XP7 and higher } + { because in XP6 the number of aircraft is not user-adjustable. The parameter} + { is ignored. } + XPLM_MSG_AIRPLANE_COUNT_CHANGED = 105; + +{$IFDEF XPLM200} +CONST + { This message is sent to your plugin whenever a plane is unloaded. The } + { parameter contains the index number of the plane being unloaded; 0 } + { indicates the user's plane. The parameter is of type int, passed as the } + { value of the pointer. (That is: the parameter is an int, not a pointer to } + { an int.) } + XPLM_MSG_PLANE_UNLOADED = 106; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} +CONST + { This message is sent to your plugin right before X-Plane writes its } + { preferences file. You can use this for two purposes: to write your own } + { preferences, and to modify any datarefs to influence preferences output. } + { For example, if your plugin temporarily modifies saved preferences, you can} + { put them back to their default values here to avoid having the tweaks be } + { persisted if your plugin is not loaded on the next invocation of X-Plane. } + { The parameter is ignored. } + XPLM_MSG_WILL_WRITE_PREFS = 107; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { This message is sent to your plugin right after a livery is loaded for an } + { airplane. You can use this to check the new livery (via datarefs) and } + { react accordingly. The parameter contains the index number of the aircraft} + { whose livery is changing. } + XPLM_MSG_LIVERY_LOADED = 108; +{$ENDIF XPLM210} + +{$IFDEF XPLM301} +CONST + { Sent to your plugin right before X-Plane enters virtual reality mode (at } + { which time any windows that are not positioned in VR mode will no longer be} + { visible to the user). The parameter is unused and should be ignored. } + XPLM_MSG_ENTERED_VR = 109; +{$ENDIF XPLM301} + +{$IFDEF XPLM301} + { Sent to your plugin right before X-Plane leaves virtual reality mode (at } + { which time you may want to clean up windows that are positioned in VR } + { mode). The parameter is unused and should be ignored. } + XPLM_MSG_EXITING_VR = 110; +{$ENDIF XPLM301} + +{$IFDEF XPLM303} +CONST + { Sent to your plugin if another plugin wants to take over AI planes. If you } + { are a synthetic traffic provider, that probably means a plugin for an } + { online network has connected and wants to supply aircraft flown by real } + { humans and you should cease to provide synthetic traffic. If however you } + { are providing online traffic from real humans, you probably don't want to } + { disconnect, in which case you just ignore this message. The sender is the } + { plugin ID of the plugin asking for control of the planes now. You can use } + { it to find out who is requesting and whether you should yield to them. } + { Synthetic traffic providers should always yield to online networks. The } + { parameter is unused and should be ignored. } + XPLM_MSG_RELEASE_PLANES = 111; +{$ENDIF XPLM303} + + { + XPLMSendMessageToPlugin + + This function sends a message to another plug-in or X-Plane. Pass + XPLM_NO_PLUGIN_ID to broadcast to all plug-ins. Only enabled plug-ins with + a message receive function receive the message. + } + PROCEDURE XPLMSendMessageToPlugin( + inPlugin : XPLMPluginID; + inMessage : Integer; + inParam : pointer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Plugin Features API + ___________________________________________________________________________} +{ + The plugin features API allows your plugin to "sign up" for additional + capabilities and plugin system features that are normally disabled for + backward compatibility. This allows advanced plugins to "opt-in" to new + behavior. + + Each feature is defined by a permanent string name. The feature string + names will vary with the particular installation of X-Plane, so plugins + should not expect a feature to be guaranteed present. + + XPLM_WANTS_REFLECTIONS + ---------------------- + + Available in the SDK 2.0 and later for X-Plane 9, enabling this capability + causes your plugin to receive drawing hook callbacks when X-Plane builds + its off-screen reflection and shadow rendering passes. Plugins should + enable this and examine the dataref sim/graphics/view/plane_render_type to + determine whether the drawing callback is for a reflection, shadow + calculation, or the main screen. Rendering can be simlified or omitted for + reflections, and non-solid drawing should be skipped for shadow + calculations. + + **Note**: direct drawing via draw callbacks is not recommended; use the + XPLMInstance API to create object models instead. + + XPLM_USE_NATIVE_PATHS + --------------------- + + available in the SDK 2.1 and later for X-Plane 10, this modifies the plugin + system to use Unix-style paths on all operating systems. With this enabled: + + * OS X paths will match the native OS X Unix. + * Windows will use forward slashes but preserve C:\ or another drive letter + when using complete file paths. + * Linux uses its native file system path scheme. + + Without this enabled: + + * OS X will use CFM file paths separated by a colon. + * Windows will use back-slashes and conventional DOS paths. + * Linux uses its native file system path scheme. + + All plugins should enable this feature on OS X to access the native file + system. + + XPLM_USE_NATIVE_WIDGET_WINDOWS + ------------------------------ + + Available in the SDK 3.0.2 SDK, this capability tells the widgets library + to use new, modern X-Plane backed XPLMDisplay windows to anchor all widget + trees. Without it, widgets will always use legacy windows. + + Plugins should enable this to allow their widget hierarchies to respond to + the user's UI size settings and to map widget-based windwos to a VR HMD. + + Before enabling this, make sure any custom widget code in your plugin is + prepared to cope with the UI coordinate system not being th same as the + OpenGL window coordinate system. +} + + + { + XPLMFeatureEnumerator_f + + You pass an XPLMFeatureEnumerator_f to get a list of all features supported + by a given version running version of X-Plane. This routine is called once + for each feature. + } +TYPE + XPLMFeatureEnumerator_f = PROCEDURE( + inFeature : XPLMString; + inRef : pointer); cdecl; + + { + XPLMHasFeature + + This returns 1 if the given installation of X-Plane supports a feature, or + 0 if it does not. + } + FUNCTION XPLMHasFeature( + inFeature : XPLMString) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMIsFeatureEnabled + + This returns 1 if a feature is currently enabled for your plugin, or 0 if + it is not enabled. It is an error to call this routine with an unsupported + feature. + } + FUNCTION XPLMIsFeatureEnabled( + inFeature : XPLMString) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMEnableFeature + + This routine enables or disables a feature for your plugin. This will + change the running behavior of X-Plane and your plugin in some way, + depending on the feature. + } + PROCEDURE XPLMEnableFeature( + inFeature : XPLMString; + inEnable : Integer); + cdecl; external XPLM_DLL; + + { + XPLMEnumerateFeatures + + This routine calls your enumerator callback once for each feature that this + running version of X-Plane supports. Use this routine to determine all of + the features that X-Plane can support. + } + PROCEDURE XPLMEnumerateFeatures( + inEnumerator : XPLMFeatureEnumerator_f; + inRef : pointer); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMProcessing.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMProcessing.pas new file mode 100644 index 0000000..e09b6e5 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMProcessing.pas @@ -0,0 +1,254 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMProcessing; +INTERFACE +{ + This API allows you to get regular callbacks during the flight loop, the + part of X-Plane where the plane's position calculates the physics of + flight, etc. Use these APIs to accomplish periodic tasks like logging data + and performing I/O. + + You can receive a callback either just before or just after the per-frame + physics calculations happen - you can use post-FM callbacks to "patch" the + flight model after it has run. + + If the user has set the number of flight model iterations per frame greater + than one your plugin will _not_ see this; these integrations run on the + sub-section of the flight model where iterations improve responsiveness + (e.g. physical integration, not simple systems tracking) and are thus + opaque to plugins. + + Flight loop scheduling, when scheduled by time, is scheduled by a "first + callback after the deadline" schedule, e.g. your callbacks will always be + slightly late to ensure that we don't run faster than your deadline. + + WARNING: Do NOT use these callbacks to draw! You cannot draw during flight + loop callbacks. Use the drawing callbacks (see XPLMDisplay for more info) + for graphics. (One exception: you can use a post-flight loop callback to + update your own off-screen FBOs.) +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FLIGHT LOOP CALLBACKS + ___________________________________________________________________________} + +{$IFDEF XPLM210} + { + XPLMFlightLoopPhaseType + + You can register a flight loop callback to run either before or after the + flight model is integrated by X-Plane. + } +TYPE + XPLMFlightLoopPhaseType = ( + { Your callback runs before X-Plane integrates the flight model. } + xplm_FlightLoop_Phase_BeforeFlightModel = 0 + + { Your callback runs after X-Plane integrates the flight model. } + ,xplm_FlightLoop_Phase_AfterFlightModel = 1 + + ); + PXPLMFlightLoopPhaseType = ^XPLMFlightLoopPhaseType; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMFlightLoopID + + This is an opaque identifier for a flight loop callback. You can use this + identifier to easily track and remove your callbacks, or to use the new + flight loop APIs. + } + XPLMFlightLoopID = pointer; + PXPLMFlightLoopID = ^XPLMFlightLoopID; +{$ENDIF XPLM210} + + { + XPLMFlightLoop_f + + This is your flight loop callback. Each time the flight loop is iterated + through, you receive this call at the end. + + Flight loop callbacks receive a number of input timing parameters. These + input timing parameters are not particularly useful; you may need to track + your own timing data (e.g. by reading datarefs). The input parameters are: + + - inElapsedSinceLastCall: the wall time since your last callback. + - inElapsedTimeSinceLastFlightLoop: the wall time since any flight loop was + dispatched. + - inCounter: a monotonically increasing counter, bumped once per flight + loop dispatch from the sim. + - inRefcon: your own ptr constant from when you regitered yor callback. + + Your return value controls when you will next be called. + + - Return 0 to stop receiving callbacks. + - Pass a positive number to specify how many seconds until the next + callback. (You will be called at or after this time, not before.) + - Pass a negative number to specify how many loops must go by until you + are called. For example, -1.0 means call me the very next loop. + + Try to run your flight loop as infrequently as is practical, and suspend it + (using return value 0) when you do not need it; lots of flight loop + callbacks that do nothing lowers X-Plane's frame rate. + + Your callback will NOT be unregistered if you return 0; it will merely be + inactive. + } +TYPE + XPLMFlightLoop_f = FUNCTION( + inElapsedSinceLastCall: Single; + inElapsedTimeSinceLastFlightLoop: Single; + inCounter : Integer; + inRefcon : pointer) : Single; cdecl; + +{$IFDEF XPLM210} + { + XPLMCreateFlightLoop_t + + XPLMCreateFlightLoop_t contains the parameters to create a new flight loop + callback. The strsucture can be expanded in future SDKs - always set + structSize to the size of your structure in bytes. + } +TYPE + XPLMCreateFlightLoop_t = RECORD + structSize : Integer; + phase : XPLMFlightLoopPhaseType; + callbackFunc : XPLMFlightLoop_f; + refcon : pointer; + END; + PXPLMCreateFlightLoop_t = ^XPLMCreateFlightLoop_t; +{$ENDIF XPLM210} + + { + XPLMGetElapsedTime + + This routine returns the elapsed time since the sim started up in decimal + seconds. This is a wall timer; it keeps counting upward even if the sim is + pasued. + + __WARNING__: XPLMGetElapsedTime is not a very good timer! It lacks + precision in both its data type and its source. Do not attempt to use it + for timing critical applications like network multiplayer. + } + FUNCTION XPLMGetElapsedTime: Single; + cdecl; external XPLM_DLL; + + { + XPLMGetCycleNumber + + This routine returns a counter starting at zero for each sim cycle + computed/video frame rendered. + } + FUNCTION XPLMGetCycleNumber: Integer; + cdecl; external XPLM_DLL; + + { + XPLMRegisterFlightLoopCallback + + This routine registers your flight loop callback. Pass in a pointer to a + flight loop function and a refcon. inInterval defines when you will be + called. Pass in a positive number to specify seconds from registration time + to the next callback. Pass in a negative number to indicate when you will + be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to not be + called; your callback will be inactive. + + (This legacy function only installs pre-flight-loop callbacks; use + XPLMCreateFlightLoop for more control.) + } + PROCEDURE XPLMRegisterFlightLoopCallback( + inFlightLoop : XPLMFlightLoop_f; + inInterval : Single; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMUnregisterFlightLoopCallback + + This routine unregisters your flight loop callback. Do NOT call it from + your flight loop callback. Once your flight loop callback is unregistered, + it will not be called again. + + Only use this on flight loops registered via + XPLMRegisterFlightLoopCallback. + } + PROCEDURE XPLMUnregisterFlightLoopCallback( + inFlightLoop : XPLMFlightLoop_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMSetFlightLoopCallbackInterval + + This routine sets when a callback will be called. Do NOT call it from your + callback; use the return value of the callback to change your callback + interval from inside your callback. + + inInterval is formatted the same way as in XPLMRegisterFlightLoopCallback; + positive for seconds, negative for cycles, and 0 for deactivating the + callback. If inRelativeToNow is 1, times are from the time of this call; + otherwise they are from the time the callback was last called (or the time + it was registered if it has never been called. + } + PROCEDURE XPLMSetFlightLoopCallbackInterval( + inFlightLoop : XPLMFlightLoop_f; + inInterval : Single; + inRelativeToNow : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM210} + { + XPLMCreateFlightLoop + + This routine creates a flight loop callback and returns its ID. The flight + loop callback is created using the input param struct, and is inited to be + unscheduled. + } + FUNCTION XPLMCreateFlightLoop( + inParams : PXPLMCreateFlightLoop_t) : XPLMFlightLoopID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMDestroyFlightLoop + + This routine destroys a flight loop callback by ID. Only call it on flight + loops created with the newer XPLMCreateFlightLoop API. + } + PROCEDURE XPLMDestroyFlightLoop( + inFlightLoopID : XPLMFlightLoopID); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMScheduleFlightLoop + + This routine schedules a flight loop callback for future execution. If + inInterval is negative, it is run in a certain number of frames based on + the absolute value of the input. If the interval is positive, it is a + duration in seconds. + + If inRelativeToNow is true, ties are interpretted relative to the time this + routine is called; otherwise they are relative to the last call time or the + time the flight loop was registered (if never called). + } + PROCEDURE XPLMScheduleFlightLoop( + inFlightLoopID : XPLMFlightLoopID; + inInterval : Single; + inRelativeToNow : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMScenery.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMScenery.pas new file mode 100644 index 0000000..a585830 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMScenery.pas @@ -0,0 +1,434 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMScenery; +INTERFACE +{ + This package contains APIs to interact with X-Plane's scenery system. +} + +USES + XPLMDefs; + {$A4} +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Terrain Y-Testing + ___________________________________________________________________________} +{ + The Y-testing API allows you to locate the physical scenery mesh. This + would be used to place dynamic graphics on top of the ground in a plausible + way or do physics interactions. + + The Y-test API works via probe objects, which are allocated by your plugin + and used to query terrain. Probe objects exist both to capture which + algorithm you have requested (see probe types) and also to cache query + information. + + Performance Guidelines + ---------------------- + + It is generally faster to use the same probe for nearby points and + different probes for different points. Try not to allocate more than + "hundreds" of probes at most. Share probes if you need more. Generally, + probing operations are expensive, and should be avoided via caching when + possible. + + Y testing returns a location on the terrain, a normal vectory, and a + velocity vector. The normal vector tells you the slope of the terrain at + that point. The velocity vector tells you if that terrain is moving (and is + in meters/second). For example, if your Y test hits the aircraft carrier + deck, this tells you the velocity of that point on the deck. + + Note: the Y-testing API is limited to probing the loaded scenery area, + which is approximately 300x300 km in X-Plane 9. Probes outside this area + will return the height of a 0 MSL sphere. +} + + + { + XPLMProbeType + + XPLMProbeType defines the type of terrain probe - each probe has a + different algorithm. (Only one type of probe is provided right now, but + future APIs will expose more flexible or poewrful or useful probes. + } +TYPE + XPLMProbeType = ( + { The Y probe gives you the location of the tallest physical scenery along } + { the Y axis going through the queried point. } + xplm_ProbeY = 0 + + ); + PXPLMProbeType = ^XPLMProbeType; + + { + XPLMProbeResult + + Probe results - possible results from a probe query. + } + XPLMProbeResult = ( + { The probe hit terrain and returned valid values. } + xplm_ProbeHitTerrain = 0 + + { An error in the API call. Either the probe struct size is bad, or the } + { probe is invalid or the type is mismatched for the specific query call. } + ,xplm_ProbeError = 1 + + { The probe call succeeded but there is no terrain under this point (perhaps } + { it is off the side of the planet?) } + ,xplm_ProbeMissed = 2 + + ); + PXPLMProbeResult = ^XPLMProbeResult; + + { + XPLMProbeRef + + An XPLMProbeRef is an opaque handle to a probe, used for querying the + terrain. + } + XPLMProbeRef = pointer; + PXPLMProbeRef = ^XPLMProbeRef; + + { + XPLMProbeInfo_t + + XPLMProbeInfo_t contains the results of a probe call. Make sure to set + structSize to the size of the struct before using it. + } + XPLMProbeInfo_t = RECORD + { Size of structure in bytes - always set this before calling the XPLM. } + structSize : Integer; + { Resulting X location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationX : Single; + { Resulting Y location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationY : Single; + { Resulting Z location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationZ : Single; + { X component of the normal vector to the terrain we found. } + normalX : Single; + { Y component of the normal vector to the terrain we found. } + normalY : Single; + { Z component of the normal vector to the terrain we found. } + normalZ : Single; + { X component of the velocity vector of the terrain we found. } + velocityX : Single; + { Y component of the velocity vector of the terrain we found. } + velocityY : Single; + { Z component of the velocity vector of the terrain we found. } + velocityZ : Single; + { Tells if the surface we hit is water (otherwise it is land). } + is_wet : Integer; + END; + PXPLMProbeInfo_t = ^XPLMProbeInfo_t; + + { + XPLMCreateProbe + + Creates a new probe object of a given type and returns. + } + FUNCTION XPLMCreateProbe( + inProbeType : XPLMProbeType) : XPLMProbeRef; + cdecl; external XPLM_DLL; + + { + XPLMDestroyProbe + + Deallocates an existing probe object. + } + PROCEDURE XPLMDestroyProbe( + inProbe : XPLMProbeRef); + cdecl; external XPLM_DLL; + + { + XPLMProbeTerrainXYZ + + Probes the terrain. Pass in the XYZ coordinate of the probe point, a probe + object, and an XPLMProbeInfo_t struct that has its structSize member set + properly. Other fields are filled in if we hit terrain, and a probe result + is returned. + } + FUNCTION XPLMProbeTerrainXYZ( + inProbe : XPLMProbeRef; + inX : Single; + inY : Single; + inZ : Single; + outInfo : PXPLMProbeInfo_t) : XPLMProbeResult; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * Magnetic Variation + ___________________________________________________________________________} +{ + Use the magnetic variation (more properly, the "magnetic declination") API + to find the offset of magnetic north from true north at a given latitude + and longitude within the simulator. + + In the real world, the Earth's magnetic field is irregular, such that true + north (the direction along a meridian toward the north pole) does not + necessarily match what a magnetic compass shows as north. + + Using this API ensures that you present the same offsets to users as + X-Plane's built-in instruments. +} + + + { + XPLMGetMagneticVariation + + Returns X-Plane's simulated magnetic variation (declination) at the + indication latitude and longitude. + } + FUNCTION XPLMGetMagneticVariation( + latitude : Real; + longitude : Real) : Single; + cdecl; external XPLM_DLL; + + { + XPLMDegTrueToDegMagnetic + + Converts a heading in degrees relative to true north into a value relative + to magnetic north at the user's current location. + } + FUNCTION XPLMDegTrueToDegMagnetic( + headingDegreesTrue : Single) : Single; + cdecl; external XPLM_DLL; + + { + XPLMDegMagneticToDegTrue + + Converts a heading in degrees relative to magnetic north at the user's + current location into a value relative to true north. + } + FUNCTION XPLMDegMagneticToDegTrue( + headingDegreesMagnetic: Single) : Single; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{___________________________________________________________________________ + * Object Drawing + ___________________________________________________________________________} +{ + The object drawing routines let you load and draw X-Plane OBJ files. + Objects are loaded by file path and managed via an opaque handle. X-Plane + naturally reference counts objects, so it is important that you balance + every successful call to XPLMLoadObject with a call to XPLMUnloadObject! +} + + +{$IFDEF XPLM200} +TYPE + { + XPLMObjectRef + + An XPLMObjectRef is a opaque handle to an .obj file that has been loaded + into memory. + } + XPLMObjectRef = pointer; + PXPLMObjectRef = ^XPLMObjectRef; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMDrawInfo_t + + The XPLMDrawInfo_t structure contains positioning info for one object that + is to be drawn. Be sure to set structSize to the size of the structure for + future expansion. + } + XPLMDrawInfo_t = RECORD + { Set this to the size of this structure! } + structSize : Integer; + { X location of the object in local coordinates. } + x : Single; + { Y location of the object in local coordinates. } + y : Single; + { Z location of the object in local coordinates. } + z : Single; + { Pitch in degres to rotate the object, positive is up. } + pitch : Single; + { Heading in local coordinates to rotate the object, clockwise. } + heading : Single; + { Roll to rotate the object. } + roll : Single; + END; + PXPLMDrawInfo_t = ^XPLMDrawInfo_t; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} + { + XPLMObjectLoaded_f + + You provide this callback when loading an object asynchronously; it will be + called once the object is loaded. Your refcon is passed back. The object + ref passed in is the newly loaded object (ready for use) or NULL if an + error occured. + + If your plugin is disabled, this callback will be delivered as soon as the + plugin is re-enabled. If your plugin is unloaded before this callback is + ever called, the SDK will release the object handle for you. + } +TYPE + XPLMObjectLoaded_f = PROCEDURE( + inObject : XPLMObjectRef; + inRefcon : pointer); cdecl; +{$ENDIF XPLM210} + +{$IFDEF XPLM200} + { + XPLMLoadObject + + This routine loads an OBJ file and returns a handle to it. If X-Plane has + already loaded the object, the handle to the existing object is returned. + Do not assume you will get the same handle back twice, but do make sure to + call unload once for every load to avoid "leaking" objects. The object will + be purged from memory when no plugins and no scenery are using it. + + The path for the object must be relative to the X-System base folder. If + the path is in the root of the X-System folder you may need to prepend ./ + to it; loading objects in the root of the X-System folder is STRONGLY + discouraged - your plugin should not dump art resources in the root folder! + + XPLMLoadObject will return NULL if the object cannot be loaded (either + because it is not found or the file is misformatted). This routine will + load any object that can be used in the X-Plane scenery system. + + It is important that the datarefs an object uses for animation already be + loaded before you load the object. For this reason it may be necessary to + defer object loading until the sim has fully started. + } + FUNCTION XPLMLoadObject( + inPath : XPLMString) : XPLMObjectRef; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} + { + XPLMLoadObjectAsync + + This routine loads an object asynchronously; control is returned to you + immediately while X-Plane loads the object. The sim will not stop flying + while the object loads. For large objects, it may be several seconds before + the load finishes. + + You provide a callback function that is called once the load has completed. + Note that if the object cannot be loaded, you will not find out until the + callback function is called with a NULL object handle. + + There is no way to cancel an asynchronous object load; you must wait for + the load to complete and then release the object if it is no longer + desired. + } + PROCEDURE XPLMLoadObjectAsync( + inPath : XPLMString; + inCallback : XPLMObjectLoaded_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMDrawObjects + + __Deprecation Warning__: use XPLMInstancing to draw 3-d objects by creating + instances, rather than these APIs from draw callbacks. + + XPLMDrawObjects draws an object from an OBJ file one or more times. You + pass in the object and an array of XPLMDrawInfo_t structs, one for each + place you would like the object to be drawn. + + X-Plane will attempt to cull the objects based on LOD and visibility, and + will pick the appropriate LOD. + + Lighting is a boolean; pass 1 to show the night version of object with + night-only lights lit up. Pass 0 to show the daytime version of the object. + + earth_relative controls the coordinate system. If this is 1, the rotations + you specify are applied to the object after its coordinate system is + transformed from local to earth-relative coordinates -- that is, an object + with no rotations will point toward true north and the Y axis will be up + against gravity. If this is 0, the object is drawn with your rotations from + local coordanates -- that is, an object with no rotations is drawn pointing + down the -Z axis and the Y axis of the object matches the local coordinate + Y axis. + } + PROCEDURE XPLMDrawObjects( + inObject : XPLMObjectRef; + inCount : Integer; + inLocations : PXPLMDrawInfo_t; + lighting : Integer; + earth_relative : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM200} + { + XPLMUnloadObject + + This routine marks an object as no longer being used by your plugin. + Objects are reference counted: once no plugins are using an object, it is + purged from memory. Make sure to call XPLMUnloadObject once for each + successful call to XPLMLoadObject. + } + PROCEDURE XPLMUnloadObject( + inObject : XPLMObjectRef); + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Library Access + ___________________________________________________________________________} +{ + The library access routines allow you to locate scenery objects via the + X-Plane library system. Right now library access is only provided for + objects, allowing plugin-drawn objects to be extended using the library + system. +} + + + { + XPLMLibraryEnumerator_f + + An XPLMLibraryEnumerator_f is a callback you provide that is called once + for each library element that is located. The returned paths will be + relative to the X-System folder. + } +TYPE + XPLMLibraryEnumerator_f = PROCEDURE( + inFilePath : XPLMString; + inRef : pointer); cdecl; + + { + XPLMLookupObjects + + This routine looks up a virtual path in the library system and returns all + matching elements. You provide a callback - one virtual path may match many + objects in the library. XPLMLookupObjects returns the number of objects + found. + + The latitude and longitude parameters specify the location the object will + be used. The library system allows for scenery packages to only provide + objects to certain local locations. Only objects that are allowed at the + latitude/longitude you provide will be returned. + } + FUNCTION XPLMLookupObjects( + inPath : XPLMString; + inLatitude : Single; + inLongitude : Single; + enumerator : XPLMLibraryEnumerator_f; + ref : pointer) : Integer; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMUtilities.pas b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMUtilities.pas new file mode 100644 index 0000000..121e28b --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/Delphi/XPLM/XPLMUtilities.pas @@ -0,0 +1,951 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMUtilities; +INTERFACE + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FILE UTILITIES + ___________________________________________________________________________} +{ + The XPLMUtilities file APIs provide some basic file and path functions for + use with X-Plane. + + Directory Separators + -------------------- + + The XPLM has two modes it can work in: + + * X-Plane native paths: all paths are UTF8 strings, using the unix forward + slash (/) as the directory separating character. In native path mode, + you use the same path format for all three operating systems. + + * Legacy OS paths: the directroy separator is \ for Windows, : for OS X, + and / for Linux; OS paths are encoded in MacRoman for OS X using legacy + HFS conventions, use the application code page for multi-byte encoding + on Unix using DOS path conventions, and use UTF-8 for Linux. + + While legacy OS paths are the default, we strongly encourage you to opt in + to native paths using the XPLMEnableFeature API. + + * All OS X plugins should enable native paths all of the time; if you do + not do this, you will have to convert all paths back from HFS to Unix + (and deal with MacRoman) - code written using native paths and the C + file APIs "just works" on OS X. + + * For Linux plugins, there is no difference between the two encodings. + + * Windows plugins will need to convert the UTF8 file paths to UTF16 for + use with the "wide" APIs. While it might seem tempting to stick with + legacy OS paths (and just use the "ANSI" Windows APIs), X-Plane is fully + unicode-capable, and will often be installed in paths where the user's + directories have no ACP encoding. + + Full and Relative Paths + ----------------------- + + Some of these APIs use full paths, but others use paths relative to the + user's X-Plane installation. This is documented on a per-API basis. +} + + +{$IFDEF XPLM200} + { + XPLMDataFileType + + These enums define types of data files you can load or unload using the + SDK. + } +TYPE + XPLMDataFileType = ( + { A situation (.sit) file, which starts off a flight in a given } + { configuration. } + xplm_DataFile_Situation = 1 + + { A situation movie (.smo) file, which replays a past flight. } + ,xplm_DataFile_ReplayMovie = 2 + + ); + PXPLMDataFileType = ^XPLMDataFileType; +{$ENDIF XPLM200} + + { + XPLMGetSystemPath + + This function returns the full path to the X-System folder. Note that this + is a directory path, so it ends in a trailing : or /. + + The buffer you pass should be at least 512 characters long. The path is + returned using the current native or OS path conventions. + } + PROCEDURE XPLMGetSystemPath( + outSystemPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetPrefsPath + + This routine returns a full path to a file that is within X-Plane's + preferences directory. (You should remove the file name back to the last + directory separator to get the preferences directory using + XPLMExtractFileAndPath.) + + The buffer you pass should be at least 512 characters long. The path is + returned using the current native or OS path conventions. + } + PROCEDURE XPLMGetPrefsPath( + outPrefsPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetDirectorySeparator + + This routine returns a string with one char and a null terminator that is + the directory separator for the current platform. This allows you to write + code that concatinates directory paths without having to #ifdef for + platform. The character returned will reflect the current file path mode. + } + FUNCTION XPLMGetDirectorySeparator: XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMExtractFileAndPath + + Given a full path to a file, this routine separates the path from the file. + If the path is a partial directory (e.g. ends in : or \) the trailing + directory separator is removed. This routine works in-place; a pointer to + the file part of the buffer is returned; the original buffer still starts + with the path and is null terminated with no trailing separator. + } + FUNCTION XPLMExtractFileAndPath( + inFullPath : XPLMString) : XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMGetDirectoryContents + + This routine returns a list of files in a directory (specified by a full + path, no trailing : or \). The output is returned as a list of NULL + terminated strings. An index array (if specified) is filled with pointers + into the strings. The last file is indicated by a zero-length string (and + NULL in the indices). This routine will return 1 if you had capacity for + all files or 0 if you did not. You can also skip a given number of files. + + * inDirectoryPath - a null terminated C string containing the full path to + the directory with no trailing directory char. + + * inFirstReturn - the zero-based index of the first file in the directory + to return. (Usually zero to fetch all in one pass.) + + * outFileNames - a buffer to receive a series of sequential null + terminated C-string file names. A zero-length C string will be appended + to the very end. + + * inFileNameBufSize - the size of the file name buffer in bytes. + + * outIndices - a pointer to an array of character pointers that will + become an index into the directory. The last file will be followed by a + NULL value. Pass NULL if you do not want indexing information. + + * inIndexCount - the max size of the index in entries. + + * outTotalFiles - if not NULL, this is filled in with the number of files + in the directory. + + * outReturnedFiles - if not NULL, the number of files returned by this + iteration. + + Return value: 1 if all info could be returned, 0 if there was a buffer + overrun. + + WARNING: Before X-Plane 7 this routine did not properly iterate through + directories. If X-Plane + 6 compatibility is needed, use your own code to iterate directories. + } + FUNCTION XPLMGetDirectoryContents( + inDirectoryPath : XPLMString; + inFirstReturn : Integer; + outFileNames : XPLMString; + inFileNameBufSize : Integer; + outIndices : PXPLMString; { Can be nil } + inIndexCount : Integer; + outTotalFiles : PInteger; { Can be nil } + outReturnedFiles : PInteger) : Integer; { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMLoadDataFile + + Loads a data file of a given type. Paths must be relative to the X-System + folder. To clear the replay, pass a NULL file name (this is only valid with + replay movies, not sit files). + } + FUNCTION XPLMLoadDataFile( + inFileType : XPLMDataFileType; + inFilePath : XPLMString) : Integer; { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMSaveDataFile + + Saves the current situation or replay; paths are relative to the X-System + folder. + } + FUNCTION XPLMSaveDataFile( + inFileType : XPLMDataFileType; + inFilePath : XPLMString) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{___________________________________________________________________________ + * X-PLANE MISC + ___________________________________________________________________________} + + { + XPLMHostApplicationID + + While the plug-in SDK is only accessible to plugins running inside X-Plane, + the original authors considered extending the API to other applications + that shared basic infrastructure with X-Plane. These enumerations are + hold-overs from that original roadmap; all values other than X-Plane are + deprecated. Your plugin should never need this enumeration. + } +TYPE + XPLMHostApplicationID = ( + xplm_Host_Unknown = 0 + + ,xplm_Host_XPlane = 1 + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_PlaneMaker = 2 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_WorldMaker = 3 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_Briefer = 4 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_PartMaker = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_YoungsMod = 6 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_XAuto = 7 +{$ENDIF XPLM_DEPRECATED} + + ); + PXPLMHostApplicationID = ^XPLMHostApplicationID; + + { + XPLMLanguageCode + + These enums define what language the sim is running in. These enumerations + do not imply that the sim can or does run in all of these languages; they + simply provide a known encoding in the event that a given sim version is + localized to a certain language. + } + XPLMLanguageCode = ( + xplm_Language_Unknown = 0 + + ,xplm_Language_English = 1 + + ,xplm_Language_French = 2 + + ,xplm_Language_German = 3 + + ,xplm_Language_Italian = 4 + + ,xplm_Language_Spanish = 5 + + ,xplm_Language_Korean = 6 + +{$IFDEF XPLM200} + ,xplm_Language_Russian = 7 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + ,xplm_Language_Greek = 8 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + ,xplm_Language_Japanese = 9 +{$ENDIF XPLM200} + +{$IFDEF XPLM300} + ,xplm_Language_Chinese = 10 +{$ENDIF XPLM300} + + ); + PXPLMLanguageCode = ^XPLMLanguageCode; + +{$IFDEF XPLM200} + { + XPLMError_f + + An XPLM error callback is a function that you provide to receive debugging + information from the plugin SDK. See XPLMSetErrorCallback for more + information. NOTE: for the sake of debugging, your error callback will be + called even if your plugin is not enabled, allowing you to receive debug + info in your XPluginStart and XPluginStop callbacks. To avoid causing logic + errors in the management code, do not call any other plugin routines from + your error callback - it is only meant for catching errors in the + debugging. + } +TYPE + XPLMError_f = PROCEDURE( + inMessage : XPLMString); cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMInitialized + + Deprecated: This function returns 1 if X-Plane has properly initialized the + plug-in system. If this routine returns 0, many XPLM functions will not + work. + + NOTE: because plugins are always called from within the XPLM, there is no + need to check for initialization; it will always return 1. This routine is + deprecated - you do not need to check it before continuing within your + plugin. + } + FUNCTION XPLMInitialized: Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + { + XPLMGetVersions + + This routine returns the revision of both X-Plane and the XPLM DLL. All + versions are three-digit decimal numbers (e.g. 606 for version 6.06 of + X-Plane); the current revision of the XPLM is 200 (2.00). This routine also + returns the host ID of the app running us. + + The most common use of this routine is to special-case around X-Plane + version-specific behavior. + } + PROCEDURE XPLMGetVersions( + outXPlaneVersion : PInteger; + outXPLMVersion : PInteger; + outHostID : PXPLMHostApplicationID); + cdecl; external XPLM_DLL; + + { + XPLMGetLanguage + + This routine returns the langauge the sim is running in. + } + FUNCTION XPLMGetLanguage: XPLMLanguageCode; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMFindSymbol + + This routine will attempt to find the symbol passed in the inString + parameter. If the symbol is found a pointer the function is returned, + othewise the function will return NULL. + + You can use XPLMFindSymbol to utilize newer SDK API features without + requiring newer versions of the SDK (and X-Plane) as your minimum X-Plane + version as follows: + + * Define the XPLMnnn macro to the minimum required XPLM version you will + ship with (e.g. XPLM210 for X-Plane 10 compatibility). + + * Use XPLMGetVersions and XPLMFindSymbol to detect that the host sim is + new enough to use new functions and resolve function pointers. + + * Conditionally use the new functions if and only if XPLMFindSymbol only + returns a non- NULL pointer. + + Warning: you should always check the XPLM API version as well as the + results of XPLMFindSymbol to determine if funtionality is safe to use. + + To use functionality via XPLMFindSymbol you will need to copy your own + definitions of the X-Plane API prototypes and cast the returned pointer to + the correct type. + } + FUNCTION XPLMFindSymbol( + inString : XPLMString) : pointer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMSetErrorCallback + + XPLMSetErrorCallback installs an error-reporting callback for your plugin. + Normally the plugin system performs minimum diagnostics to maximize + performance. When you install an error callback, you will receive calls due + to certain plugin errors, such as passing bad parameters or incorrect data. + + Important: the error callback determines *programming* errors, e.g. bad API + parameters. Every error that is returned by the error callback represents a + mistake in your plugin that you should fix. Error callbacks are not used to + report expected run-time problems (e.g. disk I/O errors). + + The intention is for you to install the error callback during debug + sections and put a break-point inside your callback. This will cause you to + break into the debugger from within the SDK at the point in your plugin + where you made an illegal call. + + Installing an error callback may activate error checking code that would + not normally run, and this may adversely affect performance, so do not + leave error callbacks installed in shipping plugins. Since the only useful + response to an error is to change code, error callbacks are not useful "in + the field". + } + PROCEDURE XPLMSetErrorCallback( + inCallback : XPLMError_f); + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + { + XPLMDebugString + + This routine outputs a C-style string to the Log.txt file. The file is + immediately flushed so you will not lose data. (This does cause a + performance penalty.) + + Please do *not* leave routine diagnostic logging enabled in your shipping + plugin. The X-Plane Log file is shared by X-Plane and every plugin in the + system, and plugins that (when functioning normally) print verbose log + output make it difficult for developers to find error conditions from other + parts of the system. + } + PROCEDURE XPLMDebugString( + inString : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMSpeakString + + This function displays the string in a translucent overlay over the current + display and also speaks the string if text-to-speech is enabled. The string + is spoken asynchronously, this function returns immediately. This function + may not speak or print depending on user preferences. + } + PROCEDURE XPLMSpeakString( + inString : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetVirtualKeyDescription + + Given a virtual key code (as defined in XPLMDefs.h) this routine returns a + human-readable string describing the character. This routine is provided + for showing users what keyboard mappings they have set up. The string may + read 'unknown' or be a blank or NULL string if the virtual key is unknown. + } + FUNCTION XPLMGetVirtualKeyDescription( + inVirtualKey : XPLMChar) : XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMReloadScenery + + XPLMReloadScenery reloads the current set of scenery. You can use this + function in two typical ways: simply call it to reload the scenery, picking + up any new installed scenery, .env files, etc. from disk. Or, change the + lat/ref and lon/ref data refs and then call this function to shift the + scenery environment. This routine is equivalent to picking "reload + scenery" from the developer menu. + } + PROCEDURE XPLMReloadScenery; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * X-PLANE COMMAND MANAGEMENT + ___________________________________________________________________________} +{ + The command management APIs let plugins interact with the command-system in + X-Plane, the abstraction behind keyboard presses and joystick buttons. This + API lets you create new commands and modify the behavior (or get + notification) of existing ones. + + X-Plane Command Phases + ---------------------- + + X-Plane commands are not instantaneous; they operate over a duration. + (Think of a joystick button press - you can press, hold down, and then + release the joystick button; X-Plane commands model this entire process.) + + An X-Plane command consists of three phases: a beginning, continuous + repetition, and an ending. The command may be repeated zero times in its + duration, followed by one command ending. Command begin and end messges are + balanced, but a command may be bound to more than one event source (e.g. a + keyboard key and a joystick button), in which case you may receive a second + begin during before any end). + + When you issue commands in the plugin system, you *must* balance every call + to XPLMCommandBegin with a call to XPLMCommandEnd with the same command + reference. + + Command Behavior Modification + ----------------------------- + + You can register a callback to handle a command either before or after + X-Plane does; if you receive the command before X-Plane you have the option + to either let X-Plane handle the command or hide the command from X-Plane. + This lets plugins both augment commands and replace them. + + If you register for an existing command, be sure that you are *consistent* + in letting X-Plane handle or not handle the command; you are responsible + for passing a *balanced* number of begin and end messages to X-Plane. (E.g. + it is not legal to pass all the begin messages to X-Plane but hide all the + end messages). +} + + + { + XPLMCommandPhase + + The phases of a command. + } +TYPE + XPLMCommandPhase = ( + { The command is being started. } + xplm_CommandBegin = 0 + + { The command is continuing to execute. } + ,xplm_CommandContinue = 1 + + { The command has ended. } + ,xplm_CommandEnd = 2 + + ); + PXPLMCommandPhase = ^XPLMCommandPhase; + + { + XPLMCommandRef + + A command ref is an opaque identifier for an X-Plane command. Command + references stay the same for the life of your plugin but not between + executions of X-Plane. Command refs are used to execute commands, create + commands, and create callbacks for particular commands. + + Note that a command is not "owned" by a particular plugin. Since many + plugins may participate in a command's execution, the command does not go + away if the plugin that created it is unloaded. + } + XPLMCommandRef = pointer; + PXPLMCommandRef = ^XPLMCommandRef; + + { + XPLMCommandCallback_f + + A command callback is a function in your plugin that is called when a + command is pressed. Your callback receives the command reference for the + particular command, the phase of the command that is executing, and a + reference pointer that you specify when registering the callback. + + Your command handler should return 1 to let processing of the command + continue to other plugins and X-Plane, or 0 to halt processing, potentially + bypassing X-Plane code. + } + XPLMCommandCallback_f = FUNCTION( + inCommand : XPLMCommandRef; + inPhase : XPLMCommandPhase; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMFindCommand + + XPLMFindCommand looks up a command by name, and returns its command + reference or NULL if the command does not exist. + } + FUNCTION XPLMFindCommand( + inName : XPLMString) : XPLMCommandRef; + cdecl; external XPLM_DLL; + + { + XPLMCommandBegin + + XPLMCommandBegin starts the execution of a command, specified by its + command reference. The command is "held down" until XPLMCommandEnd is + called. You must balance each XPLMCommandBegin call with an XPLMCommandEnd + call. + } + PROCEDURE XPLMCommandBegin( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCommandEnd + + XPLMCommandEnd ends the execution of a given command that was started with + XPLMCommandBegin. You must not issue XPLMCommandEnd for a command you did + not begin. + } + PROCEDURE XPLMCommandEnd( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCommandOnce + + This executes a given command momentarily, that is, the command begins and + ends immediately. This is the equivalent of calling XPLMCommandBegin() and + XPLMCommandEnd() back ot back. + } + PROCEDURE XPLMCommandOnce( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCreateCommand + + XPLMCreateCommand creates a new command for a given string. If the command + already exists, the existing command reference is returned. The description + may appear in user interface contexts, such as the joystick configuration + screen. + } + FUNCTION XPLMCreateCommand( + inName : XPLMString; + inDescription : XPLMString) : XPLMCommandRef; + cdecl; external XPLM_DLL; + + { + XPLMRegisterCommandHandler + + XPLMRegisterCommandHandler registers a callback to be called when a command + is executed. You provide a callback with a reference pointer. + + If inBefore is true, your command handler callback will be executed before + X-Plane executes the command, and returning 0 from your callback will + disable X-Plane's processing of the command. If inBefore is false, your + callback will run after X-Plane. (You can register a single callback both + before and after a command.) + } + PROCEDURE XPLMRegisterCommandHandler( + inComand : XPLMCommandRef; + inHandler : XPLMCommandCallback_f; + inBefore : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMUnregisterCommandHandler + + XPLMUnregisterCommandHandler removes a command callback registered with + XPLMRegisterCommandHandler. + } + PROCEDURE XPLMUnregisterCommandHandler( + inComand : XPLMCommandRef; + inHandler : XPLMCommandCallback_f; + inBefore : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} +{$IFDEF XPLM_DEPRECATED} +{___________________________________________________________________________ + * X-PLANE USER INTERACTION + ___________________________________________________________________________} +{ + WARNING: The legacy user interaction API is deprecated; while it was the + only way to run commands in X-Plane 6,7 and 8, it is obsolete, and was + replaced by the command system API in X-Plane 9. You should not use this + API; replace any of the calls below with XPLMCommand invocations based on + persistent command strings. The documentation that follows is for historic + reference only. + + The legacy user interaction APIs let you simulate commands the user can do + with a joystick, keyboard etc. Note that it is generally safer for future + compatibility to use one of these commands than to manipulate the + underlying sim data. +} + + + { + XPLMCommandKeyID + + These enums represent all the keystrokes available within X-Plane. They can + be sent to X-Plane directly. For example, you can reverse thrust using + these enumerations. + } +TYPE + XPLMCommandKeyID = ( + xplm_key_pause=0, + xplm_key_revthrust, + xplm_key_jettison, + xplm_key_brakesreg, + xplm_key_brakesmax, + xplm_key_gear, + xplm_key_timedn, + xplm_key_timeup, + xplm_key_fadec, + xplm_key_otto_dis, + xplm_key_otto_atr, + xplm_key_otto_asi, + xplm_key_otto_hdg, + xplm_key_otto_gps, + xplm_key_otto_lev, + xplm_key_otto_hnav, + xplm_key_otto_alt, + xplm_key_otto_vvi, + xplm_key_otto_vnav, + xplm_key_otto_nav1, + xplm_key_otto_nav2, + xplm_key_targ_dn, + xplm_key_targ_up, + xplm_key_hdgdn, + xplm_key_hdgup, + xplm_key_barodn, + xplm_key_baroup, + xplm_key_obs1dn, + xplm_key_obs1up, + xplm_key_obs2dn, + xplm_key_obs2up, + xplm_key_com1_1, + xplm_key_com1_2, + xplm_key_com1_3, + xplm_key_com1_4, + xplm_key_nav1_1, + xplm_key_nav1_2, + xplm_key_nav1_3, + xplm_key_nav1_4, + xplm_key_com2_1, + xplm_key_com2_2, + xplm_key_com2_3, + xplm_key_com2_4, + xplm_key_nav2_1, + xplm_key_nav2_2, + xplm_key_nav2_3, + xplm_key_nav2_4, + xplm_key_adf_1, + xplm_key_adf_2, + xplm_key_adf_3, + xplm_key_adf_4, + xplm_key_adf_5, + xplm_key_adf_6, + xplm_key_transpon_1, + xplm_key_transpon_2, + xplm_key_transpon_3, + xplm_key_transpon_4, + xplm_key_transpon_5, + xplm_key_transpon_6, + xplm_key_transpon_7, + xplm_key_transpon_8, + xplm_key_flapsup, + xplm_key_flapsdn, + xplm_key_cheatoff, + xplm_key_cheaton, + xplm_key_sbrkoff, + xplm_key_sbrkon, + xplm_key_ailtrimL, + xplm_key_ailtrimR, + xplm_key_rudtrimL, + xplm_key_rudtrimR, + xplm_key_elvtrimD, + xplm_key_elvtrimU, + xplm_key_forward, + xplm_key_down, + xplm_key_left, + xplm_key_right, + xplm_key_back, + xplm_key_tower, + xplm_key_runway, + xplm_key_chase, + xplm_key_free1, + xplm_key_free2, + xplm_key_spot, + xplm_key_fullscrn1, + xplm_key_fullscrn2, + xplm_key_tanspan, + xplm_key_smoke, + xplm_key_map, + xplm_key_zoomin, + xplm_key_zoomout, + xplm_key_cycledump, + xplm_key_replay, + xplm_key_tranID, + xplm_key_max + ); + PXPLMCommandKeyID = ^XPLMCommandKeyID; + + { + XPLMCommandButtonID + + These are enumerations for all of the things you can do with a joystick + button in X-Plane. They currently match the buttons menu in the equipment + setup dialog, but these enums will be stable even if they change in + X-Plane. + } + XPLMCommandButtonID = ( + xplm_joy_nothing=0, + xplm_joy_start_all, + xplm_joy_start_0, + xplm_joy_start_1, + xplm_joy_start_2, + xplm_joy_start_3, + xplm_joy_start_4, + xplm_joy_start_5, + xplm_joy_start_6, + xplm_joy_start_7, + xplm_joy_throt_up, + xplm_joy_throt_dn, + xplm_joy_prop_up, + xplm_joy_prop_dn, + xplm_joy_mixt_up, + xplm_joy_mixt_dn, + xplm_joy_carb_tog, + xplm_joy_carb_on, + xplm_joy_carb_off, + xplm_joy_trev, + xplm_joy_trm_up, + xplm_joy_trm_dn, + xplm_joy_rot_trm_up, + xplm_joy_rot_trm_dn, + xplm_joy_rud_lft, + xplm_joy_rud_cntr, + xplm_joy_rud_rgt, + xplm_joy_ail_lft, + xplm_joy_ail_cntr, + xplm_joy_ail_rgt, + xplm_joy_B_rud_lft, + xplm_joy_B_rud_rgt, + xplm_joy_look_up, + xplm_joy_look_dn, + xplm_joy_look_lft, + xplm_joy_look_rgt, + xplm_joy_glance_l, + xplm_joy_glance_r, + xplm_joy_v_fnh, + xplm_joy_v_fwh, + xplm_joy_v_tra, + xplm_joy_v_twr, + xplm_joy_v_run, + xplm_joy_v_cha, + xplm_joy_v_fr1, + xplm_joy_v_fr2, + xplm_joy_v_spo, + xplm_joy_flapsup, + xplm_joy_flapsdn, + xplm_joy_vctswpfwd, + xplm_joy_vctswpaft, + xplm_joy_gear_tog, + xplm_joy_gear_up, + xplm_joy_gear_down, + xplm_joy_lft_brake, + xplm_joy_rgt_brake, + xplm_joy_brakesREG, + xplm_joy_brakesMAX, + xplm_joy_speedbrake, + xplm_joy_ott_dis, + xplm_joy_ott_atr, + xplm_joy_ott_asi, + xplm_joy_ott_hdg, + xplm_joy_ott_alt, + xplm_joy_ott_vvi, + xplm_joy_tim_start, + xplm_joy_tim_reset, + xplm_joy_ecam_up, + xplm_joy_ecam_dn, + xplm_joy_fadec, + xplm_joy_yaw_damp, + xplm_joy_art_stab, + xplm_joy_chute, + xplm_joy_JATO, + xplm_joy_arrest, + xplm_joy_jettison, + xplm_joy_fuel_dump, + xplm_joy_puffsmoke, + xplm_joy_prerotate, + xplm_joy_UL_prerot, + xplm_joy_UL_collec, + xplm_joy_TOGA, + xplm_joy_shutdown, + xplm_joy_con_atc, + xplm_joy_fail_now, + xplm_joy_pause, + xplm_joy_rock_up, + xplm_joy_rock_dn, + xplm_joy_rock_lft, + xplm_joy_rock_rgt, + xplm_joy_rock_for, + xplm_joy_rock_aft, + xplm_joy_idle_hilo, + xplm_joy_lanlights, + xplm_joy_max + ); + PXPLMCommandButtonID = ^XPLMCommandButtonID; + + { + XPLMSimulateKeyPress + + This function simulates a key being pressed for X-Plane. The keystroke goes + directly to X-Plane; it is never sent to any plug-ins. However, since this + is a raw key stroke it may be mapped by the keys file or enter text into a + field. + + Deprecated: use XPLMCommandOnce + } + PROCEDURE XPLMSimulateKeyPress( + inKeyType : Integer; + inKey : Integer); + cdecl; external XPLM_DLL; + + { + XPLMCommandKeyStroke + + This routine simulates a command-key stroke. However, the keys are done by + function, not by actual letter, so this function works even if the user has + remapped their keyboard. Examples of things you might do with this include + pausing the simulator. + + Deprecated: use XPLMCommandOnce + } + PROCEDURE XPLMCommandKeyStroke( + inKey : XPLMCommandKeyID); + cdecl; external XPLM_DLL; + + { + XPLMCommandButtonPress + + This function simulates any of the actions that might be taken by pressing + a joystick button. However, this lets you call the command directly rather + than have to know which button is mapped where. Important: you must release + each button you press. The APIs are separate so that you can 'hold down' a + button for a fixed amount of time. + + Deprecated: use XPLMCommandBegin. + } + PROCEDURE XPLMCommandButtonPress( + inButton : XPLMCommandButtonID); + cdecl; external XPLM_DLL; + + { + XPLMCommandButtonRelease + + This function simulates any of the actions that might be taken by pressing + a joystick button. See XPLMCommandButtonPress. + + Deprecated: use XPLMCommandEnd. + } + PROCEDURE XPLMCommandButtonRelease( + inButton : XPLMCommandButtonID); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM_DEPRECATED} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDK/Libraries/Mac/XPLM.framework/XPLM b/XPLPro_Plugin_Source/SDK/SDK/Libraries/Mac/XPLM.framework/XPLM new file mode 100644 index 0000000000000000000000000000000000000000..99a7a721c0b977b5969e82367b7ef6299fccbdc7 GIT binary patch literal 566176 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 M1_2oa{^Jn%e@Hx9#Q*>R literal 0 HcmV?d00001 diff --git a/XPLPro_Plugin_Source/SDK/SDK/Libraries/Mac/XPWidgets.framework/XPWidgets b/XPLPro_Plugin_Source/SDK/SDK/Libraries/Mac/XPWidgets.framework/XPWidgets new file mode 100644 index 0000000000000000000000000000000000000000..16944beff370b45ab41c9307ee8826beddd70124 GIT binary patch literal 195312 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//.xpl + +where ABI is one of mac_x64, win_x64 or lin_x64. The new schema is preferred, +so you can pack a version of your plugin that requires 3.0 with this scheme +and include a legacy 2.x plugin using hte old scheme for X-Plane 10 +compatibility. + +Please use the new scheme where possible - having a unique file name for each +DLL makes crash reports easier to read and triage. + +The 3.0 SDK drops support for 32-bit plugins; if you need to ship a 32-bit +plugin for 32-bit X-Plane 10, shipping using two schemes and two binaries may +be the best option. + +X-Plane SDK Release 2.1.3 11/14/13 + +Fixed XPC Wrappers to use int and intptr_t instead of long. This fixes +crashes for plugins on 64-bit Windows. + +X-Plane SDK Release 2.1.2 RC2 1/15/13 + +Removed headers from frameworks, as they don't work; updated README. + +X-Plane SDK Release 2.1.2 RC1 1/12/13 + +The 2.1.2 SDK adds frameworks for the XPLM and XPWidgets; Mac developers +can link directly against these frameworks and avoid unresolved symbols +and flat namespace problems. The frameworks produce plugins that will +work on X-Plane 8, 9, and 10 depending on the plugin CPU architecture, +minimum system SDK, and XPLM API revision number. + +X-Plane SDK Release 2.1.1 RC1 10/29/12 + +The 2.1.1 update to the SDK provides 64-bit build materials. + +X-Plane SDK Release 2.1.0 RC1 3/31/12 + +This is the first release of the version 2.1 X-Plane SDK. This version of the +SDK exposes new APIs. + +This API also replaces all references to "long" with int or intptr_t, +depending on whether the integer needs to be wide enough to hold coerced +pointers. Most of the time, int is used; the notable exception is the widgets +library where params and properties can contain pointers to user data. + +This change is not an ABI change - compiled plugins will work unmodified. +However for some compilers, you may need to replace long with int or intptr_t +in your code. + +X-Plane SDK Release 2.0.1 RC1 7/21/10 + +This release adds symbol visibility macros for GCC 4 on Linux and corrects a few +function documentation comments. + +X-Plane SDK Release 2.0 RC1 7/11/08 + +This release includes a corrected XPLM.lib for windows with exports for some of +the new 2.0 APIs. + +X-Plane SDK Release 2.0 Beta 2 4/23/08 + +This release includes new APIs for reading and writing data files and drawing +hooks for the local map screen, as well as some minor tweaks: + +- Sim version is 2.0 in the headers. +- unload plane msg marked as 2.0 only. +- New enumerations for additional languages. +- Function level docs improved. + +X-Plane SDK Release 2.0 Beta 1 1/19/08 + +This is the first release of the version 2.0 X-Plane SDK. CFM support has +been removed, and the license has been simplified, reflecting that it only has +to cover the SDK include/import lib files and not the sample code or examples. + +X-Plane SDK Release 1.0.2 1/5/05 + +The headers of the SDK are modified to support Kylix. No changes for Mac, +Windows, or C users. Headers now have SDK version numbers. + +X-Plane SDK Release 1.0.1 12/29/04 + +The headers of this SDK are modified to support Linux complication. No changes +for Mac and Windows users. + +X-Plane SDK Release Candidate 1 + +Only one slight change in the enums: the enum xpProperty_SubWindowHasCloseBoxes +in XPStandardWidgets.h has been changed to xpProperty_MainWindowHasCloseBoxes. +Its value has not been changed, so you will need to search-and-replace your code +when using this version of the SDK, but already-compiled plugins will experience +no different operation. + +The documentation has been revised for all headers to revise changes made to the +SDK over the course of beta. + +X-Plane SDK Beta 5 + +This version of the SDK features a number of enumeration changes to reflect the +X-Plane interface more correctly. This became crucial when X-Plane 7's new user +interface was released. With X-Plane in release candidates hopefully beta 5 of +the SDK could be the last one. Please see: + +www.xsquawkbox.net/xpsdk/newui.html + +For a comprehensive description of all the enumeration changes. For most +plugins (no developers reported using the deprecated enumerations), a simple +search and replace should suffice. Plugins compiled against the beta 4 SDK that +do not use now-unsupported graphics will continue to work correctly. + +X-Plane SDK Beta 4 + +This release corrects two problems with the Pascal headers: function pointer +types are now declared cdecl (since this is how the SDK calls them), and the +import library for the widget callbacks is now XPWIDGETS.DLL as it should be. + +X-Plane SDK Beta 3 + +This release finally features full documentation and a stable widgets API, as +well as a few other minor bug fixes. + +Starting with beta 3, the DLLs necessary to run plugins ship with X-Plane 660. +The SDK will work with X-Plane 660 RC3 and later. The XPWidgets DLL now lives +in the Resources/plugins folder. + +Starting with beta 3, extra plugins, documentation, sample code, and sample +projects are now featured directly on the web in the new X-Plane SDK library. +They are not included in the SDK zip file; the zip file only contains headers +and lib files for the SDK. + +X-Plane SDK Beta 2 + +You must recompile your plugin for the beta 2 plugin SDK! Plugins compiled +against the beta 1 SDK will not work with X-Plane 660 or the new XPLM.DLL. + +A huge number of data refs have been added. Unfortunately the documentation +is thin. Use the data ref tester plugin to view the data refs in real time +and find what you need. + +The data ref APIs have also changed to allow for arrays of integers as well +as floats. Some sim variables are now arrays that were previously many +individual items. + +A new drawing phase is available for replacing aircraft graphics. The +texturing APIs in XPLMGraphics have been revised. The most notable change is +that you cannot use the SDK to load your textures. (This functionality was +broken and never worked in beta 1.) See the x-plane-dev list for sample code +on how to load your own bitmaps. + +X-Plane can reload plugins on the fly. Use the Plugin Enabler plugin to reload +your plugin. On the Mac you can throw the old DLL in the trash and put a new +one in its place to reload a new version of the plugin. On the PC, an alert +comes up; while this alert is up you can swap your plugins' DLL. This allows +you to recompile your plugin without rebooting the sim. + +Delphi Pascal interfaces and sample code are in the SDK. Thanks to Billy +Verreynne for his hard work on this. + diff --git a/XPLPro_Plugin_Source/SDK/SDK/license.txt b/XPLPro_Plugin_Source/SDK/SDK/license.txt new file mode 100644 index 0000000..8b9cbfc --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDK/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2008, Sandy Barbour and Ben Supnik +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Neither the names of the authors nor that of X-Plane or Laminar Research + may be used to endorse or promote products derived from this software + without specific prior written permission from the authors or + Laminar Research, respectively. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPStandardWidgets.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPStandardWidgets.h new file mode 100644 index 0000000..42d4987 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPStandardWidgets.h @@ -0,0 +1,556 @@ +#ifndef _XPStandardWidgets_h_ +#define _XPStandardWidgets_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPStandardWidgets + ***************************************************************************/ +/* + * ## THEORY OF OPERATION + * + * The standard widgets are widgets built into the widgets library. While you + * can gain access to the widget function that drives them, you generally use + * them by calling XPCreateWidget and then listening for special messages, + * etc. + * + * The standard widgets often send mesages to themselves when the user + * performs an event; these messages are sent up the widget hierarchy until + * they are handled. So you can add a widget proc directly to a push button + * (for example) to intercept the message when it is clicked, or you can put + * one widget proc on a window for all of the push buttons in the window. Most + * of these messages contain the original widget ID as a parameter so you can + * know which widget is messaging no matter who it is sent to. + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * MAIN WINDOW + ***************************************************************************/ +/* + * The main window widget class provides a "window" as the user knows it. + * These windows are dragable and can be selected. Use them to create floating + * windows and non-modal dialogs. + * + */ + + +#define xpWidgetClass_MainWindow 1 + +/* + * Main Window Type Values + * + * These type values are used to control the appearance of a main window. + * + */ +enum { + /* The standard main window; pin stripes on XP7, metal frame on XP 6. */ + xpMainWindowStyle_MainWindow = 0, + + /* A translucent dark gray window, like the one ATC messages appear in. */ + xpMainWindowStyle_Translucent = 1, + + +}; + +/* + * Main Window Properties + * + */ +enum { + /* This property specifies the type of window. Set to one of the main window * + * types above. */ + xpProperty_MainWindowType = 1100, + + /* This property specifies whether the main window has close boxes in its * + * corners. */ + xpProperty_MainWindowHasCloseBoxes = 1200, + + +}; + +/* + * MainWindow Messages + * + */ +enum { + /* This message is sent when the close buttons are pressed for your window. */ + xpMessage_CloseButtonPushed = 1200, + + +}; + +/*************************************************************************** + * SUB WINDOW + ***************************************************************************/ +/* + * X-Plane dialogs are divided into separate areas; the sub window widgets + * allow you to make these areas. Create one main window and place several + * subwindows inside it. Then place your controls inside the subwindows. + * + */ + + +#define xpWidgetClass_SubWindow 2 + +/* + * SubWindow Type Values + * + * These values control the appearance of the subwindow. + * + */ +enum { + /* A panel that sits inside a main window. */ + xpSubWindowStyle_SubWindow = 0, + + /* A screen that sits inside a panel for showing text information. */ + xpSubWindowStyle_Screen = 2, + + /* A list view for scrolling lists. */ + xpSubWindowStyle_ListView = 3, + + +}; + +/* + * SubWindow Properties + * + */ +enum { + /* This property specifies the type of window. Set to one of the subwindow * + * types above. */ + xpProperty_SubWindowType = 1200, + + +}; + +/*************************************************************************** + * BUTTON + ***************************************************************************/ +/* + * The button class provides a number of different button styles and + * behaviors, including push buttons, radio buttons, check boxes, etc. The + * button label appears on or next to the button depending on the button's + * appearance, or type. + * + * The button's behavior is a separate property that dictates who it hilights + * and what kinds of messages it sends. Since behavior and type are different, + * you can do strange things like make check boxes that act as push buttons or + * push buttons with radio button behavior. + * + * In X-Plane 6 there were no check box graphics. The result is the following + * behavior: in X-Plane + * 6 all check box and radio buttons are round (radio-button style) buttons; + * in X-Plane 7 they are all square (check-box style) buttons. In a future + * version of X-Plane, the xpButtonBehavior enums will provide the correct + * graphic (check box or radio button) giving the expected result. + * + */ + + +#define xpWidgetClass_Button 3 + +/* + * Button Types + * + * These define the visual appearance of buttons but not how they respond to + * the mouse. + * + */ +enum { + /* This is a standard push button, like an 'OK' or 'Cancel' button in a dialog* + * box. */ + xpPushButton = 0, + + /* A check box or radio button. Use this and the button behaviors below to * + * get the desired behavior. */ + xpRadioButton = 1, + + /* A window close box. */ + xpWindowCloseBox = 3, + + /* A small down arrow. */ + xpLittleDownArrow = 5, + + /* A small up arrow. */ + xpLittleUpArrow = 6, + + +}; + +/* + * Button Behavior Values + * + * These define how the button responds to mouse clicks. + * + */ +enum { + /* Standard push button behavior. The button hilites while the mouse is * + * clicked over it and unhilites when the mouse is moved outside of it or * + * released. If the mouse is released over the button, the * + * xpMsg_PushButtonPressed message is sent. */ + xpButtonBehaviorPushButton = 0, + + /* Check box behavior. The button immediately toggles its value when the mouse* + * is clicked and sends out a xpMsg_ButtonStateChanged message. */ + xpButtonBehaviorCheckBox = 1, + + /* Radio button behavior. The button immediately sets its state to one and * + * sends out a xpMsg_ButtonStateChanged message if it was not already set to * + * one. You must turn off other radio buttons in a group in your code. */ + xpButtonBehaviorRadioButton = 2, + + +}; + +/* + * Button Properties + * + */ +enum { + /* This property sets the visual type of button. Use one of the button types * + * above. */ + xpProperty_ButtonType = 1300, + + /* This property sets the button's behavior. Use one of the button behaviors * + * above. */ + xpProperty_ButtonBehavior = 1301, + + /* This property tells whether a check box or radio button is "checked" or * + * not. Not used for push buttons. */ + xpProperty_ButtonState = 1302, + + +}; + +/* + * Button Messages + * + * These messages are sent by the button to itself and then up the widget + * chain when the button is clicked. (You may intercept them by providing a + * widget handler for the button itself or by providing a handler in a parent + * widget.) + * + */ +enum { + /* This message is sent when the user completes a click and release in a * + * button with push button behavior. Parameter one of the message is the * + * widget ID of the button. This message is dispatched up the widget * + * hierarchy. */ + xpMsg_PushButtonPressed = 1300, + + /* This message is sent when a button is clicked that has radio button or * + * check box behavior and its value changes. (Note that if the value changes * + * by setting a property you do not receive this message!) Parameter one is * + * the widget ID of the button, parameter 2 is the new state value, either * + * zero or one. This message is dispatched up the widget hierarchy. */ + xpMsg_ButtonStateChanged = 1301, + + +}; + +/*************************************************************************** + * TEXT FIELD + ***************************************************************************/ +/* + * The text field widget provides an editable text field including mouse + * selection and keyboard navigation. The contents of the text field are its + * descriptor. (The descriptor changes as the user types.) + * + * The text field can have a number of types, that effect the visual layout of + * the text field. The text field sends messages to itself so you may control + * its behavior. + * + * If you need to filter keystrokes, add a new handler and intercept the key + * press message. Since key presses are passed by pointer, you can modify the + * keystroke and pass it through to the text field widget. + * + * WARNING: in X-Plane before 7.10 (including 6.70) null characters could + * crash X-Plane. To prevent this, wrap this object with a filter function + * (more instructions can be found on the SDK website). + * + */ + + +#define xpWidgetClass_TextField 4 + +/* + * Text Field Type Values + * + * These control the look of the text field. + * + */ +enum { + /* A field for text entry. */ + xpTextEntryField = 0, + + /* A transparent text field. The user can type and the text is drawn, but no * + * background is drawn. You can draw your own background by adding a widget * + * handler and prehandling the draw message. */ + xpTextTransparent = 3, + + /* A translucent edit field, dark gray. */ + xpTextTranslucent = 4, + + +}; + +/* + * Text Field Properties + * + */ +enum { + /* This is the character position the selection starts at, zero based. If it * + * is the same as the end insertion point, the insertion point is not a * + * selection. */ + xpProperty_EditFieldSelStart = 1400, + + /* This is the character position of the end of the selection. */ + xpProperty_EditFieldSelEnd = 1401, + + /* This is the character position a drag was started at if the user is * + * dragging to select text, or -1 if a drag is not in progress. */ + xpProperty_EditFieldSelDragStart = 1402, + + /* This is the type of text field to display, from the above list. */ + xpProperty_TextFieldType = 1403, + + /* Set this property to 1 to password protect the field. Characters will be * + * drawn as *s even though the descriptor will contain plain-text. */ + xpProperty_PasswordMode = 1404, + + /* The max number of characters you can enter, if limited. Zero means * + * unlimited. */ + xpProperty_MaxCharacters = 1405, + + /* The first visible character on the left. This effectively scrolls the text* + * field. */ + xpProperty_ScrollPosition = 1406, + + /* The font to draw the field's text with. (An XPLMFontID.) */ + xpProperty_Font = 1407, + + /* This is the active side of the insert selection. (Internal) */ + xpProperty_ActiveEditSide = 1408, + + +}; + +/* + * Text Field Messages + * + */ +enum { + /* The text field sends this message to itself when its text changes. It sends* + * the message up the call chain; param1 is the text field's widget ID. */ + xpMsg_TextFieldChanged = 1400, + + +}; + +/*************************************************************************** + * SCROLL BAR + ***************************************************************************/ +/* + * A standard scroll bar or slider control. The scroll bar has a minimum, + * maximum and current value that is updated when the user drags it. The + * scroll bar sends continuous messages as it is dragged. + * + */ + + +#define xpWidgetClass_ScrollBar 5 + +/* + * Scroll Bar Type Values + * + * This defines how the scroll bar looks. + * + */ +enum { + /* A standard X-Plane scroll bar (with arrows on the ends). */ + xpScrollBarTypeScrollBar = 0, + + /* A slider, no arrows. */ + xpScrollBarTypeSlider = 1, + + +}; + +/* + * Scroll Bar Properties + * + */ +enum { + /* The current position of the thumb (in between the min and max, inclusive) */ + xpProperty_ScrollBarSliderPosition = 1500, + + /* The value the scroll bar has when the thumb is in the lowest position. */ + xpProperty_ScrollBarMin = 1501, + + /* The value the scroll bar has when the thumb is in the highest position. */ + xpProperty_ScrollBarMax = 1502, + + /* How many units to move the scroll bar when clicking next to the thumb. The * + * scroll bar always moves one unit when the arrows are clicked. */ + xpProperty_ScrollBarPageAmount = 1503, + + /* The type of scrollbar from the enums above. */ + xpProperty_ScrollBarType = 1504, + + /* Used internally. */ + xpProperty_ScrollBarSlop = 1505, + + +}; + +/* + * Scroll Bar Messages + * + */ +enum { + /* The scroll bar sends this message when the slider position changes. It * + * sends the message up the call chain; param1 is the Scroll Bar widget ID. */ + xpMsg_ScrollBarSliderPositionChanged = 1500, + + +}; + +/*************************************************************************** + * CAPTION + ***************************************************************************/ +/* + * A caption is a simple widget that shows its descriptor as a string, useful + * for labeling parts of a window. It always shows its descriptor as its + * string and is otherwise transparent. + * + */ + + +#define xpWidgetClass_Caption 6 + +/* + * Caption Properties + * + */ +enum { + /* This property specifies whether the caption is lit; use lit captions * + * against screens. */ + xpProperty_CaptionLit = 1600, + + +}; + +/*************************************************************************** + * GENERAL GRAPHICS + ***************************************************************************/ +/* + * The general graphics widget can show one of many icons available from + * X-Plane. + * + */ + + +#define xpWidgetClass_GeneralGraphics 7 + +/* + * General Graphics Types Values + * + * These define the icon for the general graphics. + * + */ +enum { + xpShip = 4, + + xpILSGlideScope = 5, + + xpMarkerLeft = 6, + + xp_Airport = 7, + + xpNDB = 8, + + xpVOR = 9, + + xpRadioTower = 10, + + xpAircraftCarrier = 11, + + xpFire = 12, + + xpMarkerRight = 13, + + xpCustomObject = 14, + + xpCoolingTower = 15, + + xpSmokeStack = 16, + + xpBuilding = 17, + + xpPowerLine = 18, + + xpVORWithCompassRose = 19, + + xpOilPlatform = 21, + + xpOilPlatformSmall = 22, + + xpWayPoint = 23, + + +}; + +/* + * General Graphics Properties + * + */ +enum { + /* This property controls the type of icon that is drawn. */ + xpProperty_GeneralGraphicsType = 1700, + + +}; + +/*************************************************************************** + * PROGRESS INDICATOR + ***************************************************************************/ +/* + * This widget implements a progress indicator as seen when X-Plane starts up. + * + */ + +#define xpWidgetClass_Progress 8 + +/* + * Progress Indicator Properties + * + */ +enum { + /* This is the current value of the progress indicator. */ + xpProperty_ProgressPosition = 1800, + + /* This is the minimum value, equivalent to 0% filled. */ + xpProperty_ProgressMin = 1801, + + /* This is the maximum value, equivalent to 100% filled. */ + xpProperty_ProgressMax = 1802, + + +}; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPUIGraphics.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPUIGraphics.h new file mode 100644 index 0000000..b70e0f6 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPUIGraphics.h @@ -0,0 +1,354 @@ +#ifndef _XPUIGraphics_h_ +#define _XPUIGraphics_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPUIGraphics + ***************************************************************************/ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * UI GRAPHICS + ***************************************************************************/ + +/* + * XPWindowStyle + * + * There are a few built-in window styles in X-Plane that you can use. + * + * Note that X-Plane 6 does not offer real shadow-compositing; you must make + * sure to put a window on top of another window of the right style to the + * shadows work, etc. This applies to elements with insets and shadows. The + * rules are: + * + * Sub windows must go on top of main windows, and screens and list views on + * top of subwindows. Only help and main windows can be over the main screen. + * + * With X-Plane 7 any window or element may be placed over any other element. + * + * Some windows are scaled by stretching, some by repeating. The drawing + * routines know which scaling method to use. The list view cannot be rescaled + * in X-Plane 6 because it has both a repeating pattern and a gradient in one + * element. All other elements can be rescaled. + * + */ +enum { + /* An LCD screen that shows help. */ + xpWindow_Help = 0, + + /* A dialog box window. */ + xpWindow_MainWindow = 1, + + /* A panel or frame within a dialog box window. */ + xpWindow_SubWindow = 2, + + /* An LCD screen within a panel to hold text displays. */ + xpWindow_Screen = 4, + + /* A list view within a panel for scrolling file names, etc. */ + xpWindow_ListView = 5, + + +}; +typedef int XPWindowStyle; + +/* + * XPDrawWindow + * + * This routine draws a window of the given dimensions at the given offset on + * the virtual screen in a given style. The window is automatically scaled as + * appropriate using a bitmap scaling technique (scaling or repeating) as + * appropriate to the style. + * + */ +WIDGET_API void XPDrawWindow( + int inX1, + int inY1, + int inX2, + int inY2, + XPWindowStyle inStyle); + +/* + * XPGetWindowDefaultDimensions + * + * This routine returns the default dimensions for a window. Output is either + * a minimum or fixed value depending on whether the window is scalable. + * + */ +WIDGET_API void XPGetWindowDefaultDimensions( + XPWindowStyle inStyle, + int * outWidth, /* Can be NULL */ + int * outHeight); /* Can be NULL */ + +/* + * XPElementStyle + * + * Elements are individually drawable UI things like push buttons, etc. The + * style defines what kind of element you are drawing. Elements can be + * stretched in one or two dimensions (depending on the element). Some + * elements can be lit. + * + * In X-Plane 6 some elements must be drawn over metal. Some are scalable and + * some are not. Any element can be drawn anywhere in X-Plane 7. + * + * Scalable Axis Required Background + * + */ +enum { + /* x metal */ + xpElement_TextField = 6, + + /* none metal */ + xpElement_CheckBox = 9, + + /* none metal */ + xpElement_CheckBoxLit = 10, + + /* none window header */ + xpElement_WindowCloseBox = 14, + + /* none window header */ + xpElement_WindowCloseBoxPressed = 15, + + /* x metal */ + xpElement_PushButton = 16, + + /* x metal */ + xpElement_PushButtonLit = 17, + + /* none any */ + xpElement_OilPlatform = 24, + + /* none any */ + xpElement_OilPlatformSmall = 25, + + /* none any */ + xpElement_Ship = 26, + + /* none any */ + xpElement_ILSGlideScope = 27, + + /* none any */ + xpElement_MarkerLeft = 28, + + /* none any */ + xpElement_Airport = 29, + + /* none any */ + xpElement_Waypoint = 30, + + /* none any */ + xpElement_NDB = 31, + + /* none any */ + xpElement_VOR = 32, + + /* none any */ + xpElement_RadioTower = 33, + + /* none any */ + xpElement_AircraftCarrier = 34, + + /* none any */ + xpElement_Fire = 35, + + /* none any */ + xpElement_MarkerRight = 36, + + /* none any */ + xpElement_CustomObject = 37, + + /* none any */ + xpElement_CoolingTower = 38, + + /* none any */ + xpElement_SmokeStack = 39, + + /* none any */ + xpElement_Building = 40, + + /* none any */ + xpElement_PowerLine = 41, + + /* none metal */ + xpElement_CopyButtons = 45, + + /* none metal */ + xpElement_CopyButtonsWithEditingGrid = 46, + + /* x, y metal */ + xpElement_EditingGrid = 47, + + /* THIS CAN PROBABLY BE REMOVED */ + xpElement_ScrollBar = 48, + + /* none any */ + xpElement_VORWithCompassRose = 49, + + /* none metal */ + xpElement_Zoomer = 51, + + /* x, y metal */ + xpElement_TextFieldMiddle = 52, + + /* none metal */ + xpElement_LittleDownArrow = 53, + + /* none metal */ + xpElement_LittleUpArrow = 54, + + /* none metal */ + xpElement_WindowDragBar = 61, + + /* none metal */ + xpElement_WindowDragBarSmooth = 62, + + +}; +typedef int XPElementStyle; + +/* + * XPDrawElement + * + * XPDrawElement draws a given element at an offset on the virtual screen in + * set dimensions. + * *Even* if the element is not scalable, it will be scaled if the width and + * height do not match the preferred dimensions; it'll just look ugly. Pass + * inLit to see the lit version of the element; if the element cannot be lit + * this is ignored. + * + */ +WIDGET_API void XPDrawElement( + int inX1, + int inY1, + int inX2, + int inY2, + XPElementStyle inStyle, + int inLit); + +/* + * XPGetElementDefaultDimensions + * + * This routine returns the recommended or minimum dimensions of a given UI + * element. outCanBeLit tells whether the element has both a lit and unlit + * state. Pass `NULL` to not receive any of these parameters. + * + */ +WIDGET_API void XPGetElementDefaultDimensions( + XPElementStyle inStyle, + int * outWidth, /* Can be NULL */ + int * outHeight, /* Can be NULL */ + int * outCanBeLit); /* Can be NULL */ + +/* + * XPTrackStyle + * + * A track is a UI element that displays a value vertically or horizontally. + * X-Plane has three kinds of tracks: scroll bars, sliders, and progress bars. + * Tracks can be displayed either horizontally or vertically; tracks will + * choose their own layout based on the larger dimension of their dimensions + * (e.g. they know if they are tall or wide). Sliders may be lit or unlit + * (showing the user manipulating them). + * + * - ScrollBar: this is a standard scroll bar with arrows and a thumb to drag. + * - Slider: this is a simple track with a ball in the middle that can be + * slid. + * - Progress: this is a progress indicator showing how a long task is going. + * + */ +enum { + /* not over metal can be lit can be rotated */ + xpTrack_ScrollBar = 0, + + /* over metal can be lit can be rotated */ + xpTrack_Slider = 1, + + /* over metal cannot be lit cannot be rotated */ + xpTrack_Progress = 2, + + +}; +typedef int XPTrackStyle; + +/* + * XPDrawTrack + * + * This routine draws a track. You pass in the track dimensions and size; the + * track picks the optimal orientation for these dimensions. Pass in the + * track's minimum current and maximum values; the indicator will be + * positioned appropriately. You can also specify whether the track is lit or + * not. + * + */ +WIDGET_API void XPDrawTrack( + int inX1, + int inY1, + int inX2, + int inY2, + int inMin, + int inMax, + int inValue, + XPTrackStyle inTrackStyle, + int inLit); + +/* + * XPGetTrackDefaultDimensions + * + * This routine returns a track's default smaller dimension; all tracks are + * scalable in the larger dimension. It also returns whether a track can be + * lit. + * + */ +WIDGET_API void XPGetTrackDefaultDimensions( + XPTrackStyle inStyle, + int * outWidth, + int * outCanBeLit); + +/* + * XPGetTrackMetrics + * + * This routine returns the metrics of a track. If you want to write UI code + * to manipulate a track, this routine helps you know where the mouse + * locations are. For most other elements, the rectangle the element is drawn + * in is enough information. However, the scrollbar drawing routine does some + * automatic placement; this routine lets you know where things ended up. You + * pass almost everything you would pass to the draw routine. You get out the + * orientation, and other useful stuff. + * + * Besides orientation, you get five dimensions for the five parts of a + * scrollbar, which are the down button, down area (area before the thumb), + * the thumb, and the up area and button. For horizontal scrollers, the left + * button decreases; for vertical scrollers, the top button decreases. + * + */ +WIDGET_API void XPGetTrackMetrics( + int inX1, + int inY1, + int inX2, + int inY2, + int inMin, + int inMax, + int inValue, + XPTrackStyle inTrackStyle, + int * outIsVertical, + int * outDownBtnSize, + int * outDownPageSize, + int * outThumbSize, + int * outUpPageSize, + int * outUpBtnSize); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgetDefs.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgetDefs.h new file mode 100644 index 0000000..c1b2341 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgetDefs.h @@ -0,0 +1,472 @@ +#ifndef _XPWidgetDefs_h_ +#define _XPWidgetDefs_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPWidgetDefs + ***************************************************************************/ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + + +#if APL + #if XPWIDGETS + #if __GNUC__ >= 4 + #define WIDGET_API __attribute__((visibility("default"))) + #elif __MACH__ + #define WIDGET_API + #else + #define WIDGET_API __declspec(dllexport) + #endif + #else + #define WIDGET_API + #endif +#elif IBM + #if XPWIDGETS + #define WIDGET_API __declspec(dllexport) + #else + #define WIDGET_API __declspec(dllimport) + #endif +#elif LIN + #if XPWIDGETS + #if __GNUC__ >= 4 + #define WIDGET_API __attribute__((visibility("default"))) + #else + #define WIDGET_API + #endif + #else + #define WIDGET_API + #endif +#else +#pragma error "Platform not defined!" +#endif + /*************************************************************************** + * WIDGET DEFINITIONS + ***************************************************************************/ +/* + * A widget is a call-back driven screen entity like a push-button, window, + * text entry field, etc. + * + * Use the widget API to create widgets of various classes. You can nest them + * into trees of widgets to create complex user interfaces. + * + */ + + +/* + * XPWidgetID + * + * A Widget ID is an opaque unique non-zero handle identifying your widget. + * Use 0 to specify "no widget". This type is defined as wide enough to hold a + * pointer. You receive a widget ID when you create a new widget and then use + * that widget ID to further refer to the widget. + * + */ +typedef void * XPWidgetID; + +/* + * XPWidgetPropertyID + * + * Properties are values attached to instances of your widgets. A property is + * identified by a 32-bit ID and its value is the width of a pointer. + * + * Each widget instance may have a property or not have it. When you set a + * property on a widget for the first time, the property is added to the + * widget; it then stays there for the life of the widget. + * + * Some property IDs are predefined by the widget package; you can make up + * your own property IDs as well. + * + */ +enum { + /* A window's refcon is an opaque value used by client code to find other data* + * based on it. */ + xpProperty_Refcon = 0, + + /* These properties are used by the utlities to implement dragging. */ + xpProperty_Dragging = 1, + + xpProperty_DragXOff = 2, + + xpProperty_DragYOff = 3, + + /* Is the widget hilited? (For widgets that support this kind of thing.) */ + xpProperty_Hilited = 4, + + /* Is there a C++ object attached to this widget? */ + xpProperty_Object = 5, + + /* If this property is 1, the widget package will use OpenGL to restrict * + * drawing to the Wiget's exposed rectangle. */ + xpProperty_Clip = 6, + + /* Is this widget enabled (for those that have a disabled state too)? */ + xpProperty_Enabled = 7, + + /* NOTE: Property IDs 1 - 999 are reserved for the widgets library. * + * * + * NOTE: Property IDs 1000 - 9999 are allocated to the standard widget classes* + * provided with the library. * + * * + * Properties 1000 - 1099 are for widget class 0, 1100 - 1199 for widget class* + * 1, etc. */ + xpProperty_UserStart = 10000, + + +}; +typedef int XPWidgetPropertyID; + +/* + * XPMouseState_t + * + * When the mouse is clicked or dragged, a pointer to this structure is passed + * to your widget function. + * + */ +typedef struct { + int x; + int y; + /* Mouse Button number, left = 0 (right button not yet supported. */ + int button; +#if defined(XPLM200) + /* Scroll wheel delta (button in this case would be the wheel axis number). */ + int delta; +#endif /* XPLM200 */ +} XPMouseState_t; + +/* + * XPKeyState_t + * + * When a key is pressed, a pointer to this struct is passed to your widget + * function. + * + */ +typedef struct { + /* The ASCII key that was pressed. WARNING: this may be 0 for some non-ASCII * + * key sequences. */ + char key; + /* The flags. Make sure to check this if you only want key-downs! */ + XPLMKeyFlags flags; + /* The virtual key code for the key */ + char vkey; +} XPKeyState_t; + +/* + * XPWidgetGeometryChange_t + * + * This structure contains the deltas for your widget's geometry when it + * changes. + * + */ +typedef struct { + int dx; + /* +Y = the widget moved up */ + int dy; + int dwidth; + int dheight; +} XPWidgetGeometryChange_t; + +/* + * XPDispatchMode + * + * The dispatching modes describe how the widgets library sends out messages. + * Currently there are three modes: + * + */ +enum { + /* The message will only be sent to the target widget. */ + xpMode_Direct = 0, + + /* The message is sent to the target widget, then up the chain of parents * + * until the message is handled or a parentless widget is reached. */ + xpMode_UpChain = 1, + + /* The message is sent to the target widget and then all of its children * + * recursively depth-first. */ + xpMode_Recursive = 2, + + /* The message is snet just to the target, but goes to every callback, even if* + * it is handled. */ + xpMode_DirectAllCallbacks = 3, + + /* The message is only sent to the very first handler even if it is not * + * accepted. (This is really only useful for some internal widget library * + * functions.) */ + xpMode_Once = 4, + + +}; +typedef int XPDispatchMode; + +/* + * XPWidgetClass + * + * Widget classes define predefined widget types. A widget class basically + * specifies from a library the widget function to be used for the widget. + * Most widgets can be made right from classes. + * + */ +typedef int XPWidgetClass; + +/* An unspecified widget class. Other widget classes are in * + * XPStandardWidgets.h */ +#define xpWidgetClass_None 0 + +/*************************************************************************** + * WIDGET MESSAGES + ***************************************************************************/ + +/* + * XPWidgetMessage + * + * Widgets receive 32-bit messages indicating what action is to be taken or + * notifications of events. The list of messages may be expanded. + * + */ +enum { + /* No message, should not be sent. */ + xpMsg_None = 0, + + /* The create message is sent once per widget that is created with your widget* + * function and once for any widget that has your widget function attached. * + * * + * Dispatching: Direct * + * * + * Param 1: 1 if you are being added as a subclass, 0 if the widget is first * + * being created. */ + xpMsg_Create = 1, + + /* The destroy message is sent once for each message that is destroyed that * + * has your widget function. * + * * + * Dispatching: Direct for all * + * * + * Param 1: 1 if being deleted by a recursive delete to the parent, 0 for * + * explicit deletion. */ + xpMsg_Destroy = 2, + + /* The paint message is sent to your widget to draw itself. The paint message * + * is the bare-bones message; in response you must draw yourself, draw your * + * children, set up clipping and culling, check for visibility, etc. If you * + * don't want to do all of this, ignore the paint message and a draw message * + * (see below) will be sent to you. * + * * + * Dispatching: Direct */ + xpMsg_Paint = 3, + + /* The draw message is sent to your widget when it is time to draw yourself. * + * OpenGL will be set up to draw in 2-d global screen coordinates, but you * + * should use the XPLM to set up OpenGL state. * + * * + * Dispatching: Direct */ + xpMsg_Draw = 4, + + /* The key press message is sent once per key that is pressed. The first * + * parameter is the type of key code (integer or char) and the second is the * + * code itself. By handling this event, you consume the key stroke. * + * * + * Handling this message 'consumes' the keystroke; not handling it passes it * + * to your parent widget. * + * * + * Dispatching: Up Chain * + * * + * Param 1: A pointer to an XPKeyState_t structure with the keystroke. */ + xpMsg_KeyPress = 5, + + /* Keyboard focus is being given to you. By handling this message you accept * + * keyboard focus. The first parameter will be one if a child of yours gave up* + * focus to you, 0 if someone set focus on you explicitly. * + * * + * Handling this message accepts focus; not handling refuses focus. * + * * + * Dispatching: direct * + * * + * Param 1: 1 if you are gaining focus because your child is giving it up, 0 * + * if someone is explicitly giving you focus. */ + xpMsg_KeyTakeFocus = 6, + + /* Keyboard focus is being taken away from you. The first parameter will be * + * one if you are losing focus because another widget is taking it, or 0 if * + * someone called the API to make you lose focus explicitly. * + * * + * Dispatching: Direct * + * * + * Param 1: 1 if focus is being taken by another widget, 0 if code requested * + * to remove focus. */ + xpMsg_KeyLoseFocus = 7, + + /* You receive one mousedown event per click with a mouse-state structure * + * pointed to by parameter 1, by accepting this you eat the click, otherwise * + * your parent gets it. You will not receive drag and mouse up messages if you* + * do not accept the down message. * + * * + * Handling this message consumes the mouse click, not handling it passes it * + * to the next widget. You can act 'transparent' as a window by never handling* + * moues clicks to certain areas. * + * * + * Dispatching: Up chain NOTE: Technically this is direct dispatched, but the * + * widgets library will shop it to each widget until one consumes the click, * + * making it effectively "up chain". * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseDown = 8, + + /* You receive a series of mouse drag messages (typically one per frame in the* + * sim) as the mouse is moved once you have accepted a mouse down message. * + * Parameter one points to a mouse-state structure describing the mouse * + * location. You will continue to receive these until the mouse button is * + * released. You may receive multiple mouse state messages with the same mouse* + * position. You will receive mouse drag events even if the mouse is dragged * + * out of your current or original bounds at the time of the mouse down. * + * * + * Dispatching: Direct * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseDrag = 9, + + /* The mouseup event is sent once when the mouse button is released after a * + * drag or click. You only receive this message if you accept the mouseDown * + * message. Parameter one points to a mouse state structure. * + * * + * Dispatching: Direct * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseUp = 10, + + /* Your geometry or a child's geometry is being changed. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the original reshaped target. * + * * + * Param 2: A pointer to a XPWidgetGeometryChange_t struct describing the * + * change. */ + xpMsg_Reshape = 11, + + /* Your exposed area has changed. * + * * + * Dispatching: Direct */ + xpMsg_ExposedChanged = 12, + + /* A child has been added to you. The child's ID is passed in parameter one. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of the child being added. */ + xpMsg_AcceptChild = 13, + + /* A child has been removed from to you. The child's ID is passed in parameter* + * one. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of the child being removed. */ + xpMsg_LoseChild = 14, + + /* You now have a new parent, or have no parent. The parent's ID is passed in,* + * or 0 for no parent. * + * * + * Dispatching: Direct * + * * + * Param 1: The Widget ID of your parent */ + xpMsg_AcceptParent = 15, + + /* You or a child has been shown. Note that this does not include you being * + * shown because your parent was shown, you were put in a new parent, your * + * root was shown, etc. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the shown widget. */ + xpMsg_Shown = 16, + + /* You have been hidden. See limitations above. * + * * + * Dispatching: Up chain * + * * + * Param 1: The widget ID of the hidden widget. */ + xpMsg_Hidden = 17, + + /* Your descriptor has changed. * + * * + * Dispatching: Direct */ + xpMsg_DescriptorChanged = 18, + + /* A property has changed. Param 1 contains the property ID. * + * * + * Dispatching: Direct * + * * + * Param 1: The Property ID being changed. * + * * + * Param 2: The new property value */ + xpMsg_PropertyChanged = 19, + +#if defined(XPLM200) + /* The mouse wheel has moved. * + * * + * Return 1 to consume the mouse wheel move, or 0 to pass the message to a * + * parent. Dispatching: Up chain * + * * + * Param 1: A pointer to an XPMouseState_t containing the mouse status. */ + xpMsg_MouseWheel = 20, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* The cursor is over your widget. If you consume this message, change the * + * XPLMCursorStatus value to indicate the desired result, with the same rules * + * as in XPLMDisplay.h. * + * * + * Return 1 to consume this message, 0 to pass it on. * + * * + * Dispatching: Up chain Param 1: A pointer to an XPMouseState_t struct * + * containing the mouse status. * + * * + * Param 2: A pointer to a XPLMCursorStatus - set this to the cursor result * + * you desire. */ + xpMsg_CursorAdjust = 21, + +#endif /* XPLM200 */ + /* NOTE: Message IDs 1000 - 9999 are allocated to the standard widget classes * + * provided with the library with 1000 - 1099 for widget class 0, 1100 - 1199 * + * for widget class 1, etc. Message IDs 10,000 and beyond are for plugin use. */ + xpMsg_UserStart = 10000, + + +}; +typedef int XPWidgetMessage; + +/*************************************************************************** + * WIDGET CALLBACK FUNCTION + ***************************************************************************/ + +/* + * XPWidgetFunc_t + * + * This function defines your custom widget's behavior. It will be called by + * the widgets library to send messages to your widget. The message and widget + * ID are passed in, as well as two ptr-width signed parameters whose meaning + * varies with the message. Return 1 to indicate that you have processed the + * message, 0 to indicate that you have not. For any message that is not + * understood, return 0. + * + */ +typedef int (* XPWidgetFunc_t)( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgetUtils.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgetUtils.h new file mode 100644 index 0000000..ff757f7 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgetUtils.h @@ -0,0 +1,232 @@ +#ifndef _XPWidgetUtils_h_ +#define _XPWidgetUtils_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPWidgetUtils + ***************************************************************************/ +/* + * ## USAGE NOTES + * + * The XPWidgetUtils library contains useful functions that make writing and + * using widgets less of a pain. + * + * One set of functions are the widget behavior functions. These functions + * each add specific useful behaviors to widgets. They can be used in two + * manners: + * + * 1. You can add a widget behavior function to a widget as a callback proc + * using the XPAddWidgetCallback function. The widget will gain that + * behavior. Remember that the last function you add has highest priority. + * You can use this to change or augment the behavior of an existing + * finished widget. + * 2. You can call a widget function from inside your own widget function. + * This allows you to include useful behaviors in custom-built widgets. A + * number of the standard widgets get their behavior from this library. To + * do this, call the behavior function from your function first. If it + * returns 1, that means it handled the event and you don't need to; simply + * return 1. + * + */ + +#include "XPWidgetDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * GENERAL UTILITIES + ***************************************************************************/ + + + +/* + * Convenience accessors + * + * It can be clumsy accessing the variables passed in by pointer to a struct + * for mouse and reshape messages; these accessors let you simply pass in the param + * right from the arguments of your widget proc and get back the value you want. + * + */ +#define MOUSE_X(param) (((XPMouseState_t *) (param))->x) +#define MOUSE_Y(param) (((XPMouseState_t *) (param))->y) + +#define DELTA_X(param) (((XPWidgetGeometryChange_t *) (param))->dx) +#define DELTA_Y(param) (((XPWidgetGeometryChange_t *) (param))->dy) +#define DELTA_W(param) (((XPWidgetGeometryChange_t *) (param))->dwidth) +#define DELTA_H(param) (((XPWidgetGeometryChange_t *) (param))->dheight) + +#define KEY_CHAR(param) (((XPKeyState_t *) (param))->key) +#define KEY_FLAGS(param) (((XPKeyState_t *) (param))->flags) +#define KEY_VKEY(param) (((XPKeyState_t *) (param))->vkey) + +#define IN_RECT(x, y, l, t, r, b) \ + (((x) >= (l)) && ((x) <= (r)) && ((y) >= (b)) && ((y) <= (t))) + +/* + * XPWidgetCreate_t + * + * This structure contains all of the parameters needed to create a wiget. It + * is used with XPUCreateWidgets to create widgets in bulk from an array. All + * parameters correspond to those of XPCreateWidget except for the container + * index. + * + * If the container index is equal to the index of a widget in the array, the + * widget in the array passed to XPUCreateWidgets is used as the parent of + * this widget. Note that if you pass an index greater than your own position + * in the array, the parent you are requesting will not exist yet. + * + * If the container index is NO_PARENT, the parent widget is specified as + * NULL. If the container index is PARAM_PARENT, the widget passed into + * XPUCreateWidgets is used. + * + */ +typedef struct { + int left; + int top; + int right; + int bottom; + int visible; + const char * descriptor; + /* Whether ethis widget is a root wiget */ + int isRoot; + /* The index of the widget to contain within, or a constant */ + int containerIndex; + XPWidgetClass widgetClass; +} XPWidgetCreate_t; + +#define NO_PARENT -1 + +#define PARAM_PARENT -2 + +#define WIDGET_COUNT(x) ((sizeof(x) / sizeof(XPWidgetCreate_t))) + +/* + * XPUCreateWidgets + * + * This function creates a series of widgets from a table (see + * XPCreateWidget_t above). Pass in an array of widget creation structures and + * an array of widget IDs that will receive each widget. + * + * Widget parents are specified by index into the created widget table, + * allowing you to create nested widget structures. You can create multiple + * widget trees in one table. Generally you should create widget trees from + * the top down. + * + * You can also pass in a widget ID that will be used when the widget's parent + * is listed as PARAM_PARENT; this allows you to embed widgets created with + * XPUCreateWidgets in a widget created previously. + * + */ +WIDGET_API void XPUCreateWidgets( + const XPWidgetCreate_t * inWidgetDefs, + int inCount, + XPWidgetID inParamParent, + XPWidgetID * ioWidgets); + +/* + * XPUMoveWidgetBy + * + * Simply moves a widget by an amount, +x = right, +y=up, without resizing the + * widget. + * + */ +WIDGET_API void XPUMoveWidgetBy( + XPWidgetID inWidget, + int inDeltaX, + int inDeltaY); + +/*************************************************************************** + * LAYOUT MANAGERS + ***************************************************************************/ +/* + * The layout managers are widget behavior functions for handling where + * widgets move. Layout managers can be called from a widget function or + * attached to a widget later. + * + */ + + +/* + * XPUFixedLayout + * + * This function causes the widget to maintain its children in fixed position + * relative to itself as it is resized. Use this on the top level 'window' + * widget for your window. + * + */ +WIDGET_API int XPUFixedLayout( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +/*************************************************************************** + * WIDGET PROC BEHAVIORS + ***************************************************************************/ +/* + * These widget behavior functions add other useful behaviors to widgets. + * These functions cannot be attached to a widget; they must be called from + * your widget function. + * + */ + + +/* + * XPUSelectIfNeeded + * + * This causes the widget to bring its window to the foreground if it is not + * already. inEatClick specifies whether clicks in the background should be + * consumed by bringin the window to the foreground. + * + */ +WIDGET_API int XPUSelectIfNeeded( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inEatClick); + +/* + * XPUDefocusKeyboard + * + * This causes a click in the widget to send keyboard focus back to X-Plane. + * This stops editing of any text fields, etc. + * + */ +WIDGET_API int XPUDefocusKeyboard( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inEatClick); + +/* + * XPUDragWidget + * + * XPUDragWidget drags the widget in response to mouse clicks. Pass in not + * only the event, but the global coordinates of the drag region, which might + * be a sub-region of your widget (for example, a title bar). + * + */ +WIDGET_API int XPUDragWidget( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2, + int inLeft, + int inTop, + int inRight, + int inBottom); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgets.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgets.h new file mode 100644 index 0000000..f4423e2 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Widgets/XPWidgets.h @@ -0,0 +1,538 @@ +#ifndef _XPWidgets_h_ +#define _XPWidgets_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPWidgets + ***************************************************************************/ +/* + * ## THEORY OF OPERATION AND NOTES + * + * Widgets are persistent view 'objects' for X-Plane. A widget is an object + * referenced by its opaque handle (widget ID) and the APIs in this file. You + * cannot access the widget's guts directly. Every Widget has the following + * intrinsic data: + * + * - A bounding box defined in global screen coordinates with 0,0 in the + * bottom left and +y = up, +x = right. + * - A visible box, which is the intersection of the bounding box with the + * widget's parents visible box. + * - Zero or one parent widgets. (Always zero if the widget is a root widget. + * - Zero or more child widgets. + * - Whether the widget is a root. Root widgets are the top level plugin + * windows. + * - Whether the widget is visible. + * - A text string descriptor, whose meaning varies from widget to widget. + * - An arbitrary set of 32 bit integral properties defined by 32-bit integral + * keys. This is how specific widgets store specific data. + * - A list of widget callbacks proc that implements the widgets behaviors. + * + * The Widgets library sends messages to widgets to request specific behaviors + * or notify the widget of things. + * + * Widgets may have more than one callback function, in which case messages + * are sent to the most recently added callback function until the message is + * handled. Messages may also be sent to parents or children; see the + * XPWidgetDefs.h header file for the different widget message dispatching + * functions. By adding a callback function to a window you can 'subclass' its + * behavior. + * + * A set of standard widgets are provided that serve common UI purposes. You + * can also customize or implement entirely custom widgets. + * + * Widgets are different than other view hierarchies (most notably Win32, + * which they bear a striking resemblance to) in the following ways: + * + * - Not all behavior can be patched. State that is managed by the XPWidgets + * DLL and not by individual widgets cannot be customized. + * - All coordinates are in global screen coordinates. Coordinates are not + * relative to an enclosing widget, nor are they relative to a display + * window. + * - Widget messages are always dispatched synchronously, and there is no + * concept of scheduling an update or a dirty region. Messages originate + * from X-Plane as the sim cycle goes by. Since X-Plane is constantly + * redrawing, so are widgets; there is no need to mark a part of a widget as + * 'needing redrawing' because redrawing happens frequently whether the + * widget needs it or not. + * - Any widget may be a 'root' widget, causing it to be drawn; there is no + * relationship between widget class and rootness. Root widgets are + * imlemented as XPLMDisply windows. + * + */ + +#include "XPWidgetDefs.h" +#include "XPLMDisplay.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * WIDGET CREATION AND MANAGEMENT + ***************************************************************************/ + +/* + * XPCreateWidget + * + * This function creates a new widget and returns the new widget's ID to you. + * If the widget creation fails for some reason, it returns NULL. Widget + * creation will fail either if you pass a bad class ID or if there is not + * adequate memory. + * + * Input Parameters: + * + * - Top, left, bottom, and right in global screen coordinates defining the + * widget's location on the screen. + * - inVisible is 1 if the widget should be drawn, 0 to start the widget as + * hidden. + * - inDescriptor is a null terminated string that will become the widget's + * descriptor. + * - inIsRoot is 1 if this is going to be a root widget, 0 if it will not be. + * - inContainer is the ID of this widget's container. It must be 0 for a root + * widget. for a non-root widget, pass the widget ID of the widget to place + * this widget within. If this widget is not going to start inside another + * widget, pass 0; this new widget will then just be floating off in space + * (and will not be drawn until it is placed in a widget. + * - inClass is the class of the widget to draw. Use one of the predefined + * class-IDs to create a standard widget. + * + * A note on widget embedding: a widget is only called (and will be drawn, + * etc.) if it is placed within a widget that will be called. Root widgets are + * always called. So it is possible to have whole chains of widgets that are + * simply not called. You can preconstruct widget trees and then place them + * into root widgets later to activate them if you wish. + * + */ +WIDGET_API XPWidgetID XPCreateWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inVisible, + const char * inDescriptor, + int inIsRoot, + XPWidgetID inContainer, + XPWidgetClass inClass); + +/* + * XPCreateCustomWidget + * + * This function is the same as XPCreateWidget except that instead of passing + * a class ID, you pass your widget callback function pointer defining the + * widget. Use this function to define a custom widget. All parameters are the + * same as XPCreateWidget, except that the widget class has been replaced with + * the widget function. + * + */ +WIDGET_API XPWidgetID XPCreateCustomWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inVisible, + const char * inDescriptor, + int inIsRoot, + XPWidgetID inContainer, + XPWidgetFunc_t inCallback); + +/* + * XPDestroyWidget + * + * This class destroys a widget. Pass in the ID of the widget to kill. If you + * pass 1 for inDestroyChilren, the widget's children will be destroyed first, + * then this widget will be destroyed. (Furthermore, the widget's children + * will be destroyed with the inDestroyChildren flag set to 1, so the + * destruction will recurse down the widget tree.) If you pass 0 for this + * flag, the child widgets will simply end up with their parent set to 0. + * + */ +WIDGET_API void XPDestroyWidget( + XPWidgetID inWidget, + int inDestroyChildren); + +/* + * XPSendMessageToWidget + * + * This sends any message to a widget. You should probably not go around + * simulating the predefined messages that the widgets library defines for + * you. You may however define custom messages for your widgets and send them + * with this method. + * + * This method supports several dispatching patterns; see XPDispatchMode for + * more info. The function returns 1 if the message was handled, 0 if it was + * not. + * + * For each widget that receives the message (see the dispatching modes), each + * widget function from the most recently installed to the oldest one receives + * the message in order until it is handled. + * + */ +WIDGET_API int XPSendMessageToWidget( + XPWidgetID inWidget, + XPWidgetMessage inMessage, + XPDispatchMode inMode, + intptr_t inParam1, + intptr_t inParam2); + +/*************************************************************************** + * WIDGET POSITIONING AND VISIBILITY + ***************************************************************************/ + +/* + * XPPlaceWidgetWithin + * + * This function changes which container a widget resides in. You may NOT use + * this function on a root widget! inSubWidget is the widget that will be + * moved. Pass a widget ID in inContainer to make inSubWidget be a child of + * inContainer. It will become the last/closest widget in the container. Pass + * 0 to remove the widget from any container. Any call to this other than + * passing the widget ID of the old parent of the affected widget will cause + * the widget to be removed from its old parent. Placing a widget within its + * own parent simply makes it the last widget. + * + * NOTE: this routine does not reposition the sub widget in global + * coordinates. If the container has layout management code, it will + * reposition the subwidget for you, otherwise you must do it with + * SetWidgetGeometry. + * + */ +WIDGET_API void XPPlaceWidgetWithin( + XPWidgetID inSubWidget, + XPWidgetID inContainer); + +/* + * XPCountChildWidgets + * + * This routine returns the number of widgets another widget contains. + * + */ +WIDGET_API int XPCountChildWidgets( + XPWidgetID inWidget); + +/* + * XPGetNthChildWidget + * + * This routine returns the widget ID of a child widget by index. Indexes are + * 0 based, from 0 to one minus the number of widgets in the parent, + * inclusive. If the index is invalid, 0 is returned. + * + */ +WIDGET_API XPWidgetID XPGetNthChildWidget( + XPWidgetID inWidget, + int inIndex); + +/* + * XPGetParentWidget + * + * Returns the parent of a widget, or 0 if the widget has no parent. Root + * widgets never have parents and therefore always return 0. + * + */ +WIDGET_API XPWidgetID XPGetParentWidget( + XPWidgetID inWidget); + +/* + * XPShowWidget + * + * This routine makes a widget visible if it is not already. Note that if a + * widget is not in a rooted widget hierarchy or one of its parents is not + * visible, it will still not be visible to the user. + * + */ +WIDGET_API void XPShowWidget( + XPWidgetID inWidget); + +/* + * XPHideWidget + * + * Makes a widget invisible. See XPShowWidget for considerations of when a + * widget might not be visible despite its own visibility state. + * + */ +WIDGET_API void XPHideWidget( + XPWidgetID inWidget); + +/* + * XPIsWidgetVisible + * + * This returns 1 if a widget is visible, 0 if it is not. Note that this + * routine takes into consideration whether a parent is invisible. Use this + * routine to tell if the user can see the widget. + * + */ +WIDGET_API int XPIsWidgetVisible( + XPWidgetID inWidget); + +/* + * XPFindRootWidget + * + * Returns the Widget ID of the root widget that contains the passed in widget + * or NULL if the passed in widget is not in a rooted hierarchy. + * + */ +WIDGET_API XPWidgetID XPFindRootWidget( + XPWidgetID inWidget); + +/* + * XPBringRootWidgetToFront + * + * This routine makes the specified widget be in the front most widget + * hierarchy. If this widget is a root widget, its widget hierarchy comes to + * front, otherwise the widget's root is brought to the front. If this widget + * is not in an active widget hiearchy (e.g. there is no root widget at the + * top of the tree), this routine does nothing. + * + */ +WIDGET_API void XPBringRootWidgetToFront( + XPWidgetID inWidget); + +/* + * XPIsWidgetInFront + * + * This routine returns true if this widget's hierarchy is the front most + * hierarchy. It returns false if the widget's hierarchy is not in front, or + * if the widget is not in a rooted hierarchy. + * + */ +WIDGET_API int XPIsWidgetInFront( + XPWidgetID inWidget); + +/* + * XPGetWidgetGeometry + * + * This routine returns the bounding box of a widget in global coordinates. + * Pass NULL for any parameter you are not interested in. + * + */ +WIDGET_API void XPGetWidgetGeometry( + XPWidgetID inWidget, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/* + * XPSetWidgetGeometry + * + * This function changes the bounding box of a widget. + * + */ +WIDGET_API void XPSetWidgetGeometry( + XPWidgetID inWidget, + int inLeft, + int inTop, + int inRight, + int inBottom); + +/* + * XPGetWidgetForLocation + * + * Given a widget and a location, this routine returns the widget ID of the + * child of that widget that owns that location. If inRecursive is true then + * this will return a child of a child of a widget as it tries to find the + * deepest widget at that location. If inVisibleOnly is true, then only + * visible widgets are considered, otherwise all widgets are considered. The + * widget ID passed for inContainer will be returned if the location is in + * that widget but not in a child widget. 0 is returned if the location is not + * in the container. + * + * NOTE: if a widget's geometry extends outside its parents geometry, it will + * not be returned by this call for mouse locations outside the parent + * geometry. The parent geometry limits the child's eligibility for mouse + * location. + * + */ +WIDGET_API XPWidgetID XPGetWidgetForLocation( + XPWidgetID inContainer, + int inXOffset, + int inYOffset, + int inRecursive, + int inVisibleOnly); + +/* + * XPGetWidgetExposedGeometry + * + * This routine returns the bounds of the area of a widget that is completely + * within its parent widgets. Since a widget's bounding box can be outside its + * parent, part of its area will not be elligible for mouse clicks and should + * not draw. Use XPGetWidgetGeometry to find out what area defines your + * widget's shape, but use this routine to find out what area to actually draw + * into. Note that the widget library does not use OpenGL clipping to keep + * frame rates up, although you could use it internally. + * + */ +WIDGET_API void XPGetWidgetExposedGeometry( + XPWidgetID inWidgetID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/*************************************************************************** + * ACCESSING WIDGET DATA + ***************************************************************************/ + +/* + * XPSetWidgetDescriptor + * + * Every widget has a descriptor, which is a text string. What the text string + * is used for varies from widget to widget; for example, a push button's text + * is its descriptor, a caption shows its descriptor, and a text field's + * descriptor is the text being edited. In other words, the usage for the text + * varies from widget to widget, but this API provides a universal and + * convenient way to get at it. While not all UI widgets need their + * descriptor, many do. + * + */ +WIDGET_API void XPSetWidgetDescriptor( + XPWidgetID inWidget, + const char * inDescriptor); + +/* + * XPGetWidgetDescriptor + * + * This routine returns the widget's descriptor. Pass in the length of the + * buffer you are going to receive the descriptor in. The descriptor will be + * null terminated for you. This routine returns the length of the actual + * descriptor; if you pass NULL for outDescriptor, you can get the + * descriptor's length without getting its text. If the length of the + * descriptor exceeds your buffer length, the buffer will not be null + * terminated (this routine has 'strncpy' semantics). + * + */ +WIDGET_API int XPGetWidgetDescriptor( + XPWidgetID inWidget, + char * outDescriptor, + int inMaxDescLength); + +/* + * XPGetWidgetUnderlyingWindow + * + * Returns the window (from the XPLMDisplay API) that backs your widget + * window. If you have opted in to modern windows, via a call to + * XPLMEnableFeature("XPLM_USE_NATIVE_WIDGET_WINDOWS", 1), you can use the + * returned window ID for display APIs like XPLMSetWindowPositioningMode(), + * allowing you to pop the widget window out into a real OS window, or move it + * into VR. + * + */ +WIDGET_API XPLMWindowID XPGetWidgetUnderlyingWindow( + XPWidgetID inWidget); + +/* + * XPSetWidgetProperty + * + * This function sets a widget's property. Properties are arbitrary values + * associated by a widget by ID. + * + */ +WIDGET_API void XPSetWidgetProperty( + XPWidgetID inWidget, + XPWidgetPropertyID inProperty, + intptr_t inValue); + +/* + * XPGetWidgetProperty + * + * This routine returns the value of a widget's property, or 0 if the property + * is not defined. If you need to know whether the property is defined, pass a + * pointer to an int for inExists; the existence of that property will be + * returned in the int. Pass NULL for inExists if you do not need this + * information. + * + */ +WIDGET_API intptr_t XPGetWidgetProperty( + XPWidgetID inWidget, + XPWidgetPropertyID inProperty, + int * inExists); /* Can be NULL */ + +/*************************************************************************** + * KEYBOARD MANAGEMENT + ***************************************************************************/ + +/* + * XPSetKeyboardFocus + * + * Controls which widget will receive keystrokes. Pass the widget ID of the + * widget to get the keys. Note that if the widget does not care about + * keystrokes, they will go to the parent widget, and if no widget cares about + * them, they go to X-Plane. + * + * If you set the keyboard focus to widget ID 0, X-Plane gets keyboard focus. + * + * This routine returns the widget ID that ended up with keyboard focus, or 0 + * for X-Plane. + * + * Keyboard focus is not changed if the new widget will not accept it. For + * setting to X-Plane, keyboard focus is always accepted. + * + */ +WIDGET_API XPWidgetID XPSetKeyboardFocus( + XPWidgetID inWidget); + +/* + * XPLoseKeyboardFocus + * + * This causes the specified widget to lose focus; focus is passed to its + * parent, or the next parent that will accept it. This routine does nothing + * if this widget does not have focus. + * + */ +WIDGET_API void XPLoseKeyboardFocus( + XPWidgetID inWidget); + +/* + * XPGetWidgetWithFocus + * + * This routine returns the widget that has keyboard focus, or 0 if X-Plane + * has keyboard focus or some other plugin window that does not have widgets + * has focus. + * + */ +WIDGET_API XPWidgetID XPGetWidgetWithFocus(void); + +/*************************************************************************** + * CREATING CUSTOM WIDGETS + ***************************************************************************/ + +/* + * XPAddWidgetCallback + * + * This function adds a new widget callback to a widget. This widget callback + * supercedes any existing ones and will receive messages first; if it does + * not handle messages they will go on to be handled by pre-existing widgets. + * + * The widget function will remain on the widget for the life of the widget. + * The creation message will be sent to the new callback immediately with the + * widget ID, and the destruction message will be sent before the other widget + * function receives a destruction message. + * + * This provides a way to 'subclass' an existing widget. By providing a second + * hook that only handles certain widget messages, you can customize or extend + * widget behavior. + * + */ +WIDGET_API void XPAddWidgetCallback( + XPWidgetID inWidget, + XPWidgetFunc_t inNewCallback); + +/* + * XPGetWidgetClassFunc + * + * Given a widget class, this function returns the callbacks that power that + * widget class. + * + */ +WIDGET_API XPWidgetFunc_t XPGetWidgetClassFunc( + XPWidgetClass inWidgetClass); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCBroadcaster.cpp b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCBroadcaster.cpp new file mode 100644 index 0000000..5fe6218 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCBroadcaster.cpp @@ -0,0 +1,56 @@ +#include "XPCBroadcaster.h" +#include "XPCListener.h" + +XPCBroadcaster::XPCBroadcaster() : + mIterator(NULL) +{ +} + +XPCBroadcaster::~XPCBroadcaster() +{ + ListenerVector::iterator iter; + mIterator = &iter; + for (iter = mListeners.begin(); iter != mListeners.end(); ++iter) + { + (*iter)->BroadcasterRemoved(this); + } +} + +void XPCBroadcaster::AddListener( + XPCListener * inListener) +{ + mListeners.push_back(inListener); + inListener->BroadcasterAdded(this); +} + +void XPCBroadcaster::RemoveListener( + XPCListener * inListener) +{ + ListenerVector::iterator iter = std::find + (mListeners.begin(), mListeners.end(), inListener); + if (iter == mListeners.end()) + return; + + if (mIterator != NULL) + { + if (*mIterator >= iter) + (*mIterator)--; + } + + mListeners.erase(iter); + inListener->BroadcasterRemoved(this); +} + +void XPCBroadcaster::BroadcastMessage( + int inMessage, + void * inParam) +{ + ListenerVector::iterator iter; + mIterator = &iter; + for (iter = mListeners.begin(); iter != mListeners.end(); ++iter) + { + (*iter)->ListenToMessage(inMessage, inParam); + } + mIterator = NULL; +} + diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCBroadcaster.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCBroadcaster.h new file mode 100644 index 0000000..8f34a05 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCBroadcaster.h @@ -0,0 +1,38 @@ +#ifndef _XPCBroadcaster_h_ +#define _XPCBroadcaster_h_ + +#include +#include + +class XPCListener; + +class XPCBroadcaster { +public: + + XPCBroadcaster(); + virtual ~XPCBroadcaster(); + + void AddListener( + XPCListener * inListener); + void RemoveListener( + XPCListener * inListener); + +protected: + + void BroadcastMessage( + int inMessage, + void * inParam=0); + +private: + + typedef std::vector ListenerVector; + + ListenerVector mListeners; + + // Reentrancy support + + ListenerVector::iterator * mIterator; + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCDisplay.cpp b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCDisplay.cpp new file mode 100644 index 0000000..fc996ca --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCDisplay.cpp @@ -0,0 +1,104 @@ +#include "XPCDisplay.h" + +XPCKeySniffer::XPCKeySniffer(int inBeforeWindows) : mBeforeWindows(inBeforeWindows) +{ + XPLMRegisterKeySniffer(KeySnifferCB, mBeforeWindows, reinterpret_cast(this)); +} + +XPCKeySniffer::~XPCKeySniffer() +{ + XPLMUnregisterKeySniffer(KeySnifferCB, mBeforeWindows, reinterpret_cast(this)); +} + + +int XPCKeySniffer::KeySnifferCB( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefCon) +{ + XPCKeySniffer * me = reinterpret_cast(inRefCon); + return me->HandleKeyStroke(inCharKey, inFlags, inVirtualKey); +} + +XPCWindow::XPCWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible) +{ + mWindow = XPLMCreateWindow(inLeft, inTop, inRight, inBottom, inIsVisible, + DrawCB, HandleKeyCB, MouseClickCB, + reinterpret_cast(this)); +} + +XPCWindow::~XPCWindow() +{ + XPLMDestroyWindow(mWindow); +} + +void XPCWindow::GetWindowGeometry( + int * outLeft, + int * outTop, + int * outRight, + int * outBottom) +{ + XPLMGetWindowGeometry(mWindow, outLeft, outTop, outRight, outBottom); +} + +void XPCWindow::SetWindowGeometry( + int inLeft, + int inTop, + int inRight, + int inBottom) +{ + XPLMSetWindowGeometry(mWindow, inLeft, inTop, inRight, inBottom); +} + +int XPCWindow::GetWindowIsVisible(void) +{ + return XPLMGetWindowIsVisible(mWindow); +} + +void XPCWindow::SetWindowIsVisible( + int inIsVisible) +{ + XPLMSetWindowIsVisible(mWindow, inIsVisible); +} + +void XPCWindow::TakeKeyboardFocus(void) +{ + XPLMTakeKeyboardFocus(mWindow); +} + +void XPCWindow::BringWindowToFront(void) +{ + XPLMBringWindowToFront(mWindow); +} + +int XPCWindow::IsWindowInFront(void) +{ + return XPLMIsWindowInFront(mWindow); +} + +void XPCWindow::DrawCB(XPLMWindowID inWindowID, void * inRefcon) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + me->DoDraw(); +} + +void XPCWindow::HandleKeyCB(XPLMWindowID inWindowID, char inKey, XPLMKeyFlags inFlags, char inVirtualKey, void * inRefcon, int losingFocus) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + if (losingFocus) + me->LoseFocus(); + else + me->HandleKey(inKey, inFlags, inVirtualKey); +} + +int XPCWindow::MouseClickCB(XPLMWindowID inWindowID, int x, int y, XPLMMouseStatus inMouse, void * inRefcon) +{ + XPCWindow * me = reinterpret_cast(inRefcon); + return me->HandleClick(x, y, inMouse); +} diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCDisplay.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCDisplay.h new file mode 100644 index 0000000..2465928 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCDisplay.h @@ -0,0 +1,73 @@ +#ifndef _XPCDisplay_h_ +#define _XPCDisplay_h_ + +#include "XPLMDisplay.h" + +class XPCKeySniffer { +public: + + XPCKeySniffer(int inBeforeWindows); + virtual ~XPCKeySniffer(); + + virtual int HandleKeyStroke( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey)=0; + +private: + + int mBeforeWindows; + + static int KeySnifferCB( + char inCharKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefCon); +}; + + + +class XPCWindow { +public: + + XPCWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible); + virtual ~XPCWindow(); + + virtual void DoDraw(void)=0; + virtual void HandleKey(char inKey, XPLMKeyFlags inFlags, char inVirtualKey)=0; + virtual void LoseFocus(void)=0; + virtual int HandleClick(int x, int y, XPLMMouseStatus inMouse)=0; + + void GetWindowGeometry( + int * outLeft, + int * outTop, + int * outRight, + int * outBottom); + void SetWindowGeometry( + int inLeft, + int inTop, + int inRight, + int inBottom); + int GetWindowIsVisible(void); + void SetWindowIsVisible( + int inIsVisible); + void TakeKeyboardFocus(void); + void BringWindowToFront(void); + int IsWindowInFront(void); + +private: + + XPLMWindowID mWindow; + + static void DrawCB(XPLMWindowID inWindowID, void * inRefcon); + static void HandleKeyCB(XPLMWindowID inWindowID, char inKey, XPLMKeyFlags inFlags, char inVirtualKey, void * inRefcon, int losingFocus); + static int MouseClickCB(XPLMWindowID inWindowID, int x, int y, XPLMMouseStatus inMouse, void * inRefcon); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCListener.cpp b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCListener.cpp new file mode 100644 index 0000000..b4c77aa --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCListener.cpp @@ -0,0 +1,27 @@ +#include "XPCListener.h" +#include "XPCBroadcaster.h" + +XPCListener::XPCListener() +{ +} + +XPCListener::~XPCListener() +{ + while (!mBroadcasters.empty()) + mBroadcasters.front()->RemoveListener(this); +} + +void XPCListener::BroadcasterAdded( + XPCBroadcaster * inBroadcaster) +{ + mBroadcasters.push_back(inBroadcaster); +} + +void XPCListener::BroadcasterRemoved( + XPCBroadcaster * inBroadcaster) +{ + BroadcastVector::iterator iter = std::find(mBroadcasters.begin(), + mBroadcasters.end(), inBroadcaster); + if (iter != mBroadcasters.end()) + mBroadcasters.erase(iter); +} diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCListener.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCListener.h new file mode 100644 index 0000000..dbdd2a0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCListener.h @@ -0,0 +1,36 @@ +#ifndef _XPCListener_h_ +#define _XPCListener_h_ + +#include +#include + +class XPCBroadcaster; + + +class XPCListener { +public: + + XPCListener(); + virtual ~XPCListener(); + + virtual void ListenToMessage( + int inMessage, + void * inParam)=0; + +private: + + typedef std::vector BroadcastVector; + + BroadcastVector mBroadcasters; + + friend class XPCBroadcaster; + + void BroadcasterAdded( + XPCBroadcaster * inBroadcaster); + + void BroadcasterRemoved( + XPCBroadcaster * inBroadcaster); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCProcessing.cpp b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCProcessing.cpp new file mode 100644 index 0000000..352c05f --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCProcessing.cpp @@ -0,0 +1,52 @@ +#include "XPCProcessing.h" +#include "XPLMUtilities.h" + +XPCProcess::XPCProcess() : + mInCallback(false), + mCallbackTime(0) +{ + XPLMRegisterFlightLoopCallback(FlightLoopCB, 0, reinterpret_cast(this)); +} + +XPCProcess::~XPCProcess() +{ + XPLMUnregisterFlightLoopCallback(FlightLoopCB, reinterpret_cast(this)); +} + +void XPCProcess::StartProcessTime(float inSeconds) +{ + mCallbackTime = inSeconds; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + +void XPCProcess::StartProcessCycles(int inCycles) +{ + mCallbackTime = -inCycles; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + +void XPCProcess::StopProcess(void) +{ + mCallbackTime = 0; + if (!mInCallback) + XPLMSetFlightLoopCallbackInterval( + FlightLoopCB, mCallbackTime, 1/*relative to now*/, reinterpret_cast(this)); +} + + +float XPCProcess::FlightLoopCB( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon) +{ + XPCProcess * me = reinterpret_cast(inRefcon); + me->mInCallback = true; + me->DoProcessing(inElapsedSinceLastCall, inElapsedTimeSinceLastFlightLoop, inCounter); + me->mInCallback = false; + return me->mCallbackTime; +} \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCProcessing.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCProcessing.h new file mode 100644 index 0000000..cd735e5 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCProcessing.h @@ -0,0 +1,37 @@ +#ifndef _XPCProcessing_h_ +#define _XPCProcessing_h_ + +#include "XPLMProcessing.h" + +class XPCProcess { +public: + + XPCProcess(); + virtual ~XPCProcess(); + + void StartProcessTime(float inSeconds); + void StartProcessCycles(int inCycles); + void StopProcess(void); + + virtual void DoProcessing( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter)=0; + +private: + + static float FlightLoopCB( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon); + + bool mInCallback; + float mCallbackTime; + + XPCProcess(const XPCProcess&); + XPCProcess& operator=(const XPCProcess&); + +}; + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidget.cpp b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidget.cpp new file mode 100644 index 0000000..8ef8aa3 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidget.cpp @@ -0,0 +1,123 @@ +#include "XPCWidget.h" + +XPCWidget::XPCWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + bool inVisible, + const char * inDescriptor, + bool inIsRoot, + XPWidgetID inParent, + XPWidgetClass inClass) : + mWidget(NULL), + mOwnsChildren(false), + mOwnsWidget(true) +{ + mWidget = XPCreateWidget( + inLeft, inTop, inRight, inBottom, + inVisible ? 1 : 0, + inDescriptor, + inIsRoot ? 1 : 0, + inIsRoot ? NULL : inParent, + inClass); + + XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); + XPAddWidgetCallback(mWidget, WidgetCallback); +} + +XPCWidget::XPCWidget( + XPWidgetID inWidget, + bool inOwnsWidget) : + mWidget(inWidget), + mOwnsChildren(false), + mOwnsWidget(inOwnsWidget) +{ + XPSetWidgetProperty(mWidget, xpProperty_Object, reinterpret_cast(this)); + XPAddWidgetCallback(mWidget, WidgetCallback); +} + +XPCWidget::~XPCWidget() +{ + if (mOwnsWidget) + XPDestroyWidget(mWidget, mOwnsChildren ? 1 : 0); +} + +void XPCWidget::SetOwnsWidget( + bool inOwnsWidget) +{ + mOwnsWidget = inOwnsWidget; +} + +void XPCWidget::SetOwnsChildren( + bool inOwnsChildren) +{ + mOwnsChildren = inOwnsChildren; +} + +XPCWidget::operator XPWidgetID () const +{ + return mWidget; +} + +XPWidgetID XPCWidget::Get(void) const +{ + return mWidget; +} + +void XPCWidget::AddAttachment( + XPCWidgetAttachment * inAttachment, + bool inOwnsAttachment, + bool inPrefilter) +{ + if (inPrefilter) + { + mAttachments.insert(mAttachments.begin(), AttachmentInfo(inAttachment, inOwnsAttachment)); + } else { + mAttachments.push_back(AttachmentInfo(inAttachment, inOwnsAttachment)); + } +} + +void XPCWidget::RemoveAttachment( + XPCWidgetAttachment * inAttachment) +{ + for (AttachmentVector::iterator iter = mAttachments.begin(); + iter != mAttachments.end(); ++iter) + { + if (iter->first == inAttachment) + { + mAttachments.erase(iter); + return; + } + } +} + +int XPCWidget::HandleWidgetMessage( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + return 0; +} + +int XPCWidget::WidgetCallback( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + XPCWidget * me = reinterpret_cast(XPGetWidgetProperty(inWidget, xpProperty_Object, NULL)); + if (me == NULL) + return 0; + + for (AttachmentVector::iterator iter = me->mAttachments.begin(); iter != + me->mAttachments.end(); ++iter) + { + int result = iter->first->HandleWidgetMessage(me, inMessage, inWidget, inParam1, inParam2); + if (result != 0) + return result; + } + + return me->HandleWidgetMessage(inMessage, inWidget, inParam1, inParam2); +} diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidget.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidget.h new file mode 100644 index 0000000..788b56a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidget.h @@ -0,0 +1,84 @@ +#ifndef _XPCWidget_h_ +#define _XPCWidget_h_ + +#include +#include +#include "XPWidgets.h" + +class XPCWidget; + +class XPCWidgetAttachment { +public: + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2)=0; + +}; + +class XPCWidget { +public: + + XPCWidget( + int inLeft, + int inTop, + int inRight, + int inBottom, + bool inVisible, + const char * inDescriptor, + bool inIsRoot, + XPWidgetID inParent, + XPWidgetClass inClass); + XPCWidget( + XPWidgetID inWidget, + bool inOwnsWidget); + virtual ~XPCWidget(); + + void SetOwnsWidget( + bool inOwnsWidget); + void SetOwnsChildren( + bool inOwnsChildren); + + operator XPWidgetID () const; + + XPWidgetID Get(void) const; + + void AddAttachment( + XPCWidgetAttachment * inAttachment, + bool inOwnsAttachment, + bool inPrefilter); + void RemoveAttachment( + XPCWidgetAttachment * inAttachment); + + virtual int HandleWidgetMessage( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + static int WidgetCallback( + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + + typedef std::pair AttachmentInfo; + typedef std::vector AttachmentVector; + + AttachmentVector mAttachments; + XPWidgetID mWidget; + bool mOwnsChildren; + bool mOwnsWidget; + + XPCWidget(); + XPCWidget(const XPCWidget&); + XPCWidget& operator=(const XPCWidget&); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidgetAttachments.cpp b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidgetAttachments.cpp new file mode 100644 index 0000000..d87f105 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidgetAttachments.cpp @@ -0,0 +1,267 @@ +#include "XPCWidgetAttachments.h" +#include "XPStandardWidgets.h" +#include "XPWidgetUtils.h" + +static void XPCGetOrderedSubWidgets( + XPWidgetID inWidget, + std::vector& outChildren); + +XPCKeyFilterAttachment::XPCKeyFilterAttachment( + const char * inValidKeys, + const char * outValidKeys) : + mInput(inValidKeys), + mOutput(outValidKeys) +{ +} + +XPCKeyFilterAttachment::~XPCKeyFilterAttachment() +{ +} + +int XPCKeyFilterAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if (inMessage == xpMsg_KeyPress) + { + char& theKey = KEY_CHAR(inParam1); + std::string::size_type pos = mInput.find(theKey); + if (pos == std::string::npos) + return 1; // Not found; eat the key! + else { + theKey = mOutput[pos]; + return 0; + } // Let it live. + } + return 0; +} + + +XPCKeyMessageAttachment::XPCKeyMessageAttachment( + char inKey, + int inMessage, + void * inParam, + bool inConsume, + bool inVkey, + XPCListener * inListener) : + mKey(inKey), mMsg(inMessage), mParam(inParam), mConsume(inConsume), + mVkey(inVkey) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCKeyMessageAttachment::~XPCKeyMessageAttachment() +{ +} + +int XPCKeyMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if (inMessage == xpMsg_KeyPress) + { + char theKey = mVkey ? KEY_VKEY(inParam1) : KEY_CHAR(inParam1); + if (theKey != mKey) + return 0; + if (!(KEY_FLAGS(inParam1) & xplm_DownFlag)) + return 0; + + BroadcastMessage(mMsg, mParam); + return mConsume ? 1 : 0; + } + return 0; +} + +XPCPushButtonMessageAttachment::XPCPushButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCPushButtonMessageAttachment::~XPCPushButtonMessageAttachment() +{ +} + +int XPCPushButtonMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_PushButtonPressed) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + if ((inMessage == xpMsg_ButtonStateChanged) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + return 0; +} + +XPCSliderMessageAttachment::XPCSliderMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCSliderMessageAttachment::~XPCSliderMessageAttachment() +{ +} + +int XPCSliderMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_ScrollBarSliderPositionChanged) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + return 0; +} + + +XPCCloseButtonMessageAttachment::XPCCloseButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener) : + mMsg(inMessage), mParam(inParam), mWidget(inWidget) +{ + if (inListener != NULL) + this->AddListener(inListener); +} + +XPCCloseButtonMessageAttachment::~XPCCloseButtonMessageAttachment() +{ +} + +int XPCCloseButtonMessageAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMessage_CloseButtonPushed) && ((XPWidgetID) inParam1 == mWidget)) + { + BroadcastMessage(mMsg, mParam); + return 1; + } + + return 0; +} + +XPCTabGroupAttachment::XPCTabGroupAttachment() +{ +} + +XPCTabGroupAttachment::~XPCTabGroupAttachment() +{ +} + +int XPCTabGroupAttachment::HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2) +{ + if ((inMessage == xpMsg_KeyPress) && (KEY_CHAR(inParam1) == XPLM_KEY_TAB) && + ((KEY_FLAGS(inParam1) & xplm_UpFlag) == 0)) + { + bool backwards = (KEY_FLAGS(inParam1) & xplm_ShiftFlag) != 0; + std::vector widgets; + XPCGetOrderedSubWidgets(inWidget, widgets); + int n, index = 0; + XPWidgetID focusWidget = XPGetWidgetWithFocus(); + std::vector::iterator iter = std::find(widgets.begin(), widgets.end(), focusWidget); + if (iter != widgets.end()) + { + index = std::distance(widgets.begin(), iter); + if (backwards) + index--; + else + index++; + if (index < 0) + index = widgets.size() - 1; + if (index >= widgets.size()) + index = 0; + } + + if (backwards) + { + for (n = index; n >= 0; --n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + for (n = widgets.size() - 1; n > index; --n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + } else { + for (n = index; n < widgets.size(); ++n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + for (n = 0; n < index; ++n) + { + if (XPGetWidgetProperty(widgets[n], xpProperty_Enabled, NULL)) + if (XPSetKeyboardFocus(widgets[n]) != NULL) + return 1; + } + } + } + return 0; +} + + + +static void XPCGetOrderedSubWidgets( + XPWidgetID inWidget, + std::vector& outChildren) +{ + outChildren.clear(); + int count = XPCountChildWidgets(inWidget); + for (int n = 0; n < count; ++n) + { + XPWidgetID child = XPGetNthChildWidget(inWidget, n); + outChildren.push_back(child); + std::vector grandChildren; + XPCGetOrderedSubWidgets(child, grandChildren); + + outChildren.insert(outChildren.end(), grandChildren.begin(), grandChildren.end()); + } +} diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidgetAttachments.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidgetAttachments.h new file mode 100644 index 0000000..91fb587 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/Wrappers/XPCWidgetAttachments.h @@ -0,0 +1,146 @@ +#ifndef _XPCWidgetAttachments_h_ +#define _XPCWidgetAttachments_h_ + +#include + +#include "XPCWidget.h" +#include "XPCBroadcaster.h" + +class XPCKeyFilterAttachment : public XPCWidgetAttachment { +public: + + XPCKeyFilterAttachment( + const char * inValidKeys, + const char * outValidKeys); + virtual ~XPCKeyFilterAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + std::string mInput; + std::string mOutput; + +}; + + +class XPCKeyMessageAttachment : public XPCWidgetAttachment, public XPCBroadcaster { +public: + + XPCKeyMessageAttachment( + char inKey, + int inMessage, + void * inParam, + bool inConsume, + bool inVkey, + XPCListener * inListener); + virtual ~XPCKeyMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + + char mKey; + bool mVkey; + int mMsg; + void * mParam; + bool mConsume; + +}; + +class XPCPushButtonMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCPushButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCPushButtonMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + +class XPCSliderMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCSliderMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCSliderMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + + +class XPCCloseButtonMessageAttachment : public XPCWidgetAttachment, XPCBroadcaster { +public: + + XPCCloseButtonMessageAttachment( + XPWidgetID inWidget, + int inMessage, + void * inParam, + XPCListener * inListener); + virtual ~XPCCloseButtonMessageAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +private: + XPWidgetID mWidget; + int mMsg; + void * mParam; +}; + +class XPCTabGroupAttachment : public XPCWidgetAttachment { +public: + + XPCTabGroupAttachment(); + virtual ~XPCTabGroupAttachment(); + + virtual int HandleWidgetMessage( + XPCWidget * inObject, + XPWidgetMessage inMessage, + XPWidgetID inWidget, + intptr_t inParam1, + intptr_t inParam2); + +}; + +#endif \ No newline at end of file diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMCamera.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMCamera.h new file mode 100644 index 0000000..db930ef --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMCamera.h @@ -0,0 +1,167 @@ +#ifndef _XPLMCamera_h_ +#define _XPLMCamera_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMCamera + ***************************************************************************/ +/* + * The XPLMCamera APIs allow plug-ins to control the camera angle in X-Plane. + * This has a number of applications, including but not limited to: + * + * - Creating new views (including dynamic/user-controllable views) for the + * user. + * - Creating applications that use X-Plane as a renderer of scenery, + * aircrafts, or both. + * + * The camera is controlled via six parameters: a location in OpenGL + * coordinates and pitch, roll and yaw, similar to an airplane's position. + * OpenGL coordinate info is described in detail in the XPLMGraphics + * documentation; generally you should use the XPLMGraphics routines to + * convert from world to local coordinates. The camera's orientation starts + * facing level with the ground directly up the negative-Z axis (approximately + * north) with the horizon horizontal. It is then rotated clockwise for yaw, + * pitched up for positive pitch, and rolled clockwise around the vector it is + * looking along for roll. + * + * You control the camera either either until the user selects a new view or + * permanently (the later being similar to how UDP camera control works). You + * control the camera by registering a callback per frame from which you + * calculate the new camera positions. This guarantees smooth camera motion. + * + * Use the XPLMDataAccess APIs to get information like the position of the + * aircraft, etc. for complex camera positioning. + * + * Note: if your goal is to move the virtual pilot in the cockpit, this API is + * not needed; simply update the datarefs for the pilot's head position. + * + * For custom exterior cameras, set the camera's mode to an external view + * first to get correct sound and 2-d panel behavior. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * CAMERA CONTROL + ***************************************************************************/ + +/* + * XPLMCameraControlDuration + * + * This enumeration states how long you want to retain control of the camera. + * You can retain it indefinitely or until the user selects a new view. + * + */ +enum { + /* Control the camera until the user picks a new view. */ + xplm_ControlCameraUntilViewChanges = 1, + + /* Control the camera until your plugin is disabled or another plugin forcably* + * takes control. */ + xplm_ControlCameraForever = 2, + + +}; +typedef int XPLMCameraControlDuration; + +/* + * XPLMCameraPosition_t + * + * This structure contains a full specification of the camera. X, Y, and Z are + * the camera's position in OpenGL coordiantes; pitch, roll, and yaw are + * rotations from a camera facing flat north in degrees. Positive pitch means + * nose up, positive roll means roll right, and positive yaw means yaw right, + * all in degrees. Zoom is a zoom factor, with 1.0 meaning normal zoom and 2.0 + * magnifying by 2x (objects appear larger). + * + */ +typedef struct { + float x; + float y; + float z; + float pitch; + float heading; + float roll; + float zoom; +} XPLMCameraPosition_t; + +/* + * XPLMCameraControl_f + * + * You use an XPLMCameraControl function to provide continuous control over + * the camera. You are passed in a structure in which to put the new camera + * position; modify it and return 1 to reposition the camera. Return 0 to + * surrender control of the camera; camera control will be handled by X-Plane + * on this draw loop. The contents of the structure as you are called are + * undefined. + * + * If X-Plane is taking camera control away from you, this function will be + * called with inIsLosingControl set to 1 and ioCameraPosition NULL. + * + */ +typedef int (* XPLMCameraControl_f)( + XPLMCameraPosition_t * outCameraPosition, /* Can be NULL */ + int inIsLosingControl, + void * inRefcon); + +/* + * XPLMControlCamera + * + * This function repositions the camera on the next drawing cycle. You must + * pass a non-null control function. Specify in inHowLong how long you'd like + * control (indefinitely or until a new view mode is set by the user). + * + */ +XPLM_API void XPLMControlCamera( + XPLMCameraControlDuration inHowLong, + XPLMCameraControl_f inControlFunc, + void * inRefcon); + +/* + * XPLMDontControlCamera + * + * This function stops you from controlling the camera. If you have a camera + * control function, it will not be called with an inIsLosingControl flag. + * X-Plane will control the camera on the next cycle. + * + * For maximum compatibility you should not use this routine unless you are in + * posession of the camera. + * + */ +XPLM_API void XPLMDontControlCamera(void); + +/* + * XPLMIsCameraBeingControlled + * + * This routine returns 1 if the camera is being controlled, zero if it is + * not. If it is and you pass in a pointer to a camera control duration, the + * current control duration will be returned. + * + */ +XPLM_API int XPLMIsCameraBeingControlled( + XPLMCameraControlDuration * outCameraControlDuration); /* Can be NULL */ + +/* + * XPLMReadCameraPosition + * + * This function reads the current camera position. + * + */ +XPLM_API void XPLMReadCameraPosition( + XPLMCameraPosition_t * outCameraPosition); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDataAccess.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDataAccess.h new file mode 100644 index 0000000..d8d1418 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDataAccess.h @@ -0,0 +1,716 @@ +#ifndef _XPLMDataAccess_h_ +#define _XPLMDataAccess_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDataAccess + ***************************************************************************/ +/* + * The data access API gives you a generic, flexible, high performance way to + * read and write data to and from X-Plane and other plug-ins. For example, + * this API allows you to read and set the nav radios, get the plane location, + * determine the current effective graphics frame rate, etc. + * + * The data access APIs are the way that you read and write data from the sim + * as well as other plugins. + * + * The API works using opaque data references. A data reference is a source of + * data; you do not know where it comes from, but once you have it you can + * read the data quickly and possibly write it. + * + * Dataref Lookup + * -------------- + * + * Data references are identified by verbose, permanent string names; by + * convention these names use path separates to form a hierarchy of datarefs, + * e.g. (sim/cockpit/radios/nav1_freq_hz). The actual opaque numeric value of + * the data reference, as returned by the XPLM API, is implementation defined + * and changes each time X-Plane is launched; therefore you need to look up + * the dataref by path every time your plugin runs. + * + * The task of looking up a data reference is relatively expensive; look up + * your data references once based on the verbose path strings, and save the + * opaque data reference value for the duration of your plugin's operation. + * Reading and writing data references is relatively fast (the cost is + * equivalent to two function calls through function pointers). + * + * X-Plane publishes over 4000 datarefs; a complete list may be found in the + * reference section of the SDK online documentation (from the SDK home page, + * choose Documentation). + * + * Dataref Types + * ------------- + * + * A note on typing: you must know the correct data type to read and write. + * APIs are provided for reading and writing data in a number of ways. You can + * also double check the data type for a data ref. Automatic type conversion + * is not done for you. + * + * Dataref types are a set, e.g. a dataref can be more than one type. When + * this happens, you can choose which API you want to use to read. For + * example, it is not uncommon for a dataref to be of type float and double. + * This means you can use either XPLMGetDatad or XPLMGetDataf to read it. + * + * Creating New Datarefs + * --------------------- + * + * X-Plane provides datarefs that come with the sim, but plugins can also + * create their own datarefs. A plugin creates a dataref by registering + * function callbacks to read and write the dataref. The XPLM will call your + * plugin each time some other plugin (or X-Plane) tries to read or write the + * dataref. You must provide a read (and optional write) callback for each + * data type you support. + * + * A note for plugins sharing data with other plugins: the load order of + * plugins is not guaranteed. To make sure that every plugin publishing data + * has published their data references before other plugins try to subscribe, + * publish your data references in your start routine but resolve them the + * first time your 'enable' routine is called, or the first time they are + * needed in code. + * + * When a plugin that created a dataref is unloaded, it becomes "orphaned". + * The dataref handle continues to be usable, but the dataref is not writable, + * and reading it will always return 0 (or 0 items for arrays). If the plugin + * is reloaded and re-registers the dataref, the handle becomes un-orphaned + * and works again. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * READING AND WRITING DATA + ***************************************************************************/ +/* + * These routines allow you to access data from within X-Plane and sometimes + * modify it. + * + */ + + +/* + * XPLMDataRef + * + * A data ref is an opaque handle to data provided by the simulator or another + * plugin. It uniquely identifies one variable (or array of variables) over + * the lifetime of your plugin. You never hard code these values; you always + * get them from XPLMFindDataRef. + * + */ +typedef void * XPLMDataRef; + +/* + * XPLMDataTypeID + * + * This is an enumeration that defines the type of the data behind a data + * reference. This allows you to sanity check that the data type matches what + * you expect. But for the most part, you will know the type of data you are + * expecting from the online documentation. + * + * Data types each take a bit field; it is legal to have a single dataref be + * more than one type of data. Whe this happens, you can pick any matching + * get/set API. + * + */ +enum { + /* Data of a type the current XPLM doesn't do. */ + xplmType_Unknown = 0, + + /* A single 4-byte integer, native endian. */ + xplmType_Int = 1, + + /* A single 4-byte float, native endian. */ + xplmType_Float = 2, + + /* A single 8-byte double, native endian. */ + xplmType_Double = 4, + + /* An array of 4-byte floats, native endian. */ + xplmType_FloatArray = 8, + + /* An array of 4-byte integers, native endian. */ + xplmType_IntArray = 16, + + /* A variable block of data. */ + xplmType_Data = 32, + + +}; +typedef int XPLMDataTypeID; + +/* + * XPLMFindDataRef + * + * Given a c-style string that names the data ref, this routine looks up the + * actual opaque XPLMDataRef that you use to read and write the data. The + * string names for datarefs are published on the X-Plane SDK web site. + * + * This function returns NULL if the data ref cannot be found. + * + * NOTE: this function is relatively expensive; save the XPLMDataRef this + * function returns for future use. Do not look up your data ref by string + * every time you need to read or write it. + * + */ +XPLM_API XPLMDataRef XPLMFindDataRef( + const char * inDataRefName); + +/* + * XPLMCanWriteDataRef + * + * Given a data ref, this routine returns true if you can successfully set the + * data, false otherwise. Some datarefs are read-only. + * + * NOTE: even if a dataref is marked writable, it may not act writable. This + * can happen for datarefs that X-Plane writes to on every frame of + * simulation. In some cases, the dataref is writable but you have to set a + * separate "override" dataref to 1 to stop X-Plane from writing it. + * + */ +XPLM_API int XPLMCanWriteDataRef( + XPLMDataRef inDataRef); + +/* + * XPLMIsDataRefGood + * + * This function returns true if the passed in handle is a valid dataref that + * is not orphaned. + * + * Note: there is normally no need to call this function; datarefs returned by + * XPLMFindDataRef remain valid (but possibly orphaned) unless there is a + * complete plugin reload (in which case your plugin is reloaded anyway). + * Orphaned datarefs can be safely read and return 0. Therefore you never need + * to call XPLMIsDataRefGood to 'check' the safety of a dataref. + * (XPLMIsDatarefGood performs some slow checking of the handle validity, so + * it has a perormance cost.) + * + */ +XPLM_API int XPLMIsDataRefGood( + XPLMDataRef inDataRef); + +/* + * XPLMGetDataRefTypes + * + * This routine returns the types of the data ref for accessor use. If a data + * ref is available in multiple data types, the bit-wise OR of these types + * will be returned. + * + */ +XPLM_API XPLMDataTypeID XPLMGetDataRefTypes( + XPLMDataRef inDataRef); + +/*************************************************************************** + * DATA ACCESSORS + ***************************************************************************/ +/* + * These routines read and write the data references. For each supported data + * type there is a reader and a writer. + * + * If the data ref is orphaned or the plugin that provides it is disabled or + * there is a type mismatch, the functions that read data will return 0 as a + * default value or not modify the passed in memory. The plugins that write + * data will not write under these circumstances or if the data ref is + * read-only. + * + * NOTE: to keep the overhead of reading datarefs low, these routines do not + * do full validation of a dataref; passing a junk value for a dataref can + * result in crashing the sim. The get/set APIs do check for NULL. + * + * For array-style datarefs, you specify the number of items to read/write and + * the offset into the array; the actual number of items read or written is + * returned. This may be less to prevent an array-out-of-bounds error. + * + */ + + +/* + * XPLMGetDatai + * + * Read an integer data ref and return its value. The return value is the + * dataref value or 0 if the dataref is NULL or the plugin is disabled. + * + */ +XPLM_API int XPLMGetDatai( + XPLMDataRef inDataRef); + +/* + * XPLMSetDatai + * + * Write a new value to an integer data ref. This routine is a no-op if the + * plugin publishing the dataref is disabled, the dataref is NULL, or the + * dataref is not writable. + * + */ +XPLM_API void XPLMSetDatai( + XPLMDataRef inDataRef, + int inValue); + +/* + * XPLMGetDataf + * + * Read a single precision floating point dataref and return its value. The + * return value is the dataref value or 0.0 if the dataref is NULL or the + * plugin is disabled. + * + */ +XPLM_API float XPLMGetDataf( + XPLMDataRef inDataRef); + +/* + * XPLMSetDataf + * + * Write a new value to a single precision floating point data ref. This + * routine is a no-op if the plugin publishing the dataref is disabled, the + * dataref is NULL, or the dataref is not writable. + * + */ +XPLM_API void XPLMSetDataf( + XPLMDataRef inDataRef, + float inValue); + +/* + * XPLMGetDatad + * + * Read a double precision floating point dataref and return its value. The + * return value is the dataref value or 0.0 if the dataref is NULL or the + * plugin is disabled. + * + */ +XPLM_API double XPLMGetDatad( + XPLMDataRef inDataRef); + +/* + * XPLMSetDatad + * + * Write a new value to a double precision floating point data ref. This + * routine is a no-op if the plugin publishing the dataref is disabled, the + * dataref is NULL, or the dataref is not writable. + * + */ +XPLM_API void XPLMSetDatad( + XPLMDataRef inDataRef, + double inValue); + +/* + * XPLMGetDatavi + * + * Read a part of an integer array dataref. If you pass NULL for outValues, + * the routine will return the size of the array, ignoring inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatavi( + XPLMDataRef inDataRef, + int * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavi + * + * Write part or all of an integer array dataref. The values passed by + * inValues are written into the dataref starting at inOffset. Up to inCount + * values are written; however if the values would write "off the end" of the + * dataref array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatavi( + XPLMDataRef inDataRef, + int * inValues, + int inoffset, + int inCount); + +/* + * XPLMGetDatavf + * + * Read a part of a single precision floating point array dataref. If you pass + * NULL for outVaules, the routine will return the size of the array, ignoring + * inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatavf( + XPLMDataRef inDataRef, + float * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavf + * + * Write part or all of a single precision floating point array dataref. The + * values passed by inValues are written into the dataref starting at + * inOffset. Up to inCount values are written; however if the values would + * write "off the end" of the dataref array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatavf( + XPLMDataRef inDataRef, + float * inValues, + int inoffset, + int inCount); + +/* + * XPLMGetDatab + * + * Read a part of a byte array dataref. If you pass NULL for outVaules, the + * routine will return the size of the array, ignoring inOffset and inMax. + * + * If outValues is not NULL, then up to inMax values are copied from the + * dataref into outValues, starting at inOffset in the dataref. If inMax + + * inOffset is larger than the size of the dataref, less than inMax values + * will be copied. The number of values copied is returned. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API int XPLMGetDatab( + XPLMDataRef inDataRef, + void * outValue, /* Can be NULL */ + int inOffset, + int inMaxBytes); + +/* + * XPLMSetDatab + * + * Write part or all of a byte array dataref. The values passed by inValues + * are written into the dataref starting at inOffset. Up to inCount values are + * written; however if the values would write "off the end" of the dataref + * array, then fewer values are written. + * + * Note: the semantics of array datarefs are entirely implemented by the + * plugin (or X-Plane) that provides the dataref, not the SDK itself; the + * above description is how these datarefs are intended to work, but a rogue + * plugin may have different behavior. + * + */ +XPLM_API void XPLMSetDatab( + XPLMDataRef inDataRef, + void * inValue, + int inOffset, + int inLength); + +/*************************************************************************** + * PUBLISHING YOUR PLUGIN'S DATA + ***************************************************************************/ +/* + * These functions allow you to create data references that other plug-ins and + * X-Plane can access via the above data access APIs. Data references + * published by other plugins operate the same as ones published by X-Plane in + * all manners except that your data reference will not be available to other + * plugins if/when your plugin is disabled. + * + * You share data by registering data provider callback functions. When a + * plug-in requests your data, these callbacks are then called. You provide + * one callback to return the value when a plugin 'reads' it and another to + * change the value when a plugin 'writes' it. + * + * Important: you must pick a prefix for your datarefs other than "sim/" - + * this prefix is reserved for X-Plane. The X-Plane SDK website contains a + * registry where authors can select a unique first word for dataref names, to + * prevent dataref collisions between plugins. + * + */ + + +/* + * XPLMGetDatai_f + * + * Data provider function pointers. + * + * These define the function pointers you provide to get or set data. Note + * that you are passed a generic pointer for each one. This is the same + * pointer you pass in your register routine; you can use it to locate plugin + * variables, etc. + * + * The semantics of your callbacks are the same as the dataref accessor above + * - basically routines like XPLMGetDatai are just pass-throughs from a caller + * to your plugin. Be particularly mindful in implementing array dataref + * read-write accessors; you are responsible for avoiding overruns, supporting + * offset read/writes, and handling a read with a NULL buffer. + * + */ +typedef int (* XPLMGetDatai_f)( + void * inRefcon); + +/* + * XPLMSetDatai_f + * + */ +typedef void (* XPLMSetDatai_f)( + void * inRefcon, + int inValue); + +/* + * XPLMGetDataf_f + * + */ +typedef float (* XPLMGetDataf_f)( + void * inRefcon); + +/* + * XPLMSetDataf_f + * + */ +typedef void (* XPLMSetDataf_f)( + void * inRefcon, + float inValue); + +/* + * XPLMGetDatad_f + * + */ +typedef double (* XPLMGetDatad_f)( + void * inRefcon); + +/* + * XPLMSetDatad_f + * + */ +typedef void (* XPLMSetDatad_f)( + void * inRefcon, + double inValue); + +/* + * XPLMGetDatavi_f + * + */ +typedef int (* XPLMGetDatavi_f)( + void * inRefcon, + int * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavi_f + * + */ +typedef void (* XPLMSetDatavi_f)( + void * inRefcon, + int * inValues, + int inOffset, + int inCount); + +/* + * XPLMGetDatavf_f + * + */ +typedef int (* XPLMGetDatavf_f)( + void * inRefcon, + float * outValues, /* Can be NULL */ + int inOffset, + int inMax); + +/* + * XPLMSetDatavf_f + * + */ +typedef void (* XPLMSetDatavf_f)( + void * inRefcon, + float * inValues, + int inOffset, + int inCount); + +/* + * XPLMGetDatab_f + * + */ +typedef int (* XPLMGetDatab_f)( + void * inRefcon, + void * outValue, /* Can be NULL */ + int inOffset, + int inMaxLength); + +/* + * XPLMSetDatab_f + * + */ +typedef void (* XPLMSetDatab_f)( + void * inRefcon, + void * inValue, + int inOffset, + int inLength); + +/* + * XPLMRegisterDataAccessor + * + * This routine creates a new item of data that can be read and written. Pass + * in the data's full name for searching, the type(s) of the data for + * accessing, and whether the data can be written to. For each data type you + * support, pass in a read accessor function and a write accessor function if + * necessary. Pass NULL for data types you do not support or write accessors + * if you are read-only. + * + * You are returned a data ref for the new item of data created. You can use + * this data ref to unregister your data later or read or write from it. + * + */ +XPLM_API XPLMDataRef XPLMRegisterDataAccessor( + const char * inDataName, + XPLMDataTypeID inDataType, + int inIsWritable, + XPLMGetDatai_f inReadInt, + XPLMSetDatai_f inWriteInt, + XPLMGetDataf_f inReadFloat, + XPLMSetDataf_f inWriteFloat, + XPLMGetDatad_f inReadDouble, + XPLMSetDatad_f inWriteDouble, + XPLMGetDatavi_f inReadIntArray, + XPLMSetDatavi_f inWriteIntArray, + XPLMGetDatavf_f inReadFloatArray, + XPLMSetDatavf_f inWriteFloatArray, + XPLMGetDatab_f inReadData, + XPLMSetDatab_f inWriteData, + void * inReadRefcon, + void * inWriteRefcon); + +/* + * XPLMUnregisterDataAccessor + * + * Use this routine to unregister any data accessors you may have registered. + * You unregister a data ref by the XPLMDataRef you get back from + * registration. Once you unregister a data ref, your function pointer will + * not be called anymore. + * + */ +XPLM_API void XPLMUnregisterDataAccessor( + XPLMDataRef inDataRef); + +/*************************************************************************** + * SHARING DATA BETWEEN MULTIPLE PLUGINS + ***************************************************************************/ +/* + * The data reference registration APIs from the previous section allow a + * plugin to publish data in a one-owner manner; the plugin that publishes the + * data reference owns the real memory that the data ref uses. This is + * satisfactory for most cases, but there are also cases where plugnis need to + * share actual data. + * + * With a shared data reference, no one plugin owns the actual memory for the + * data reference; the plugin SDK allocates that for you. When the first + * plugin asks to 'share' the data, the memory is allocated. When the data is + * changed, every plugin that is sharing the data is notified. + * + * Shared data references differ from the 'owned' data references from the + * previous section in a few ways: + * + * * With shared data references, any plugin can create the data reference; + * with owned plugins one plugin must create the data reference and others + * subscribe. (This can be a problem if you don't know which set of plugins + * will be present). + * + * * With shared data references, every plugin that is sharing the data is + * notified when the data is changed. With owned data references, only the + * one owner is notified when the data is changed. + * + * * With shared data references, you cannot access the physical memory of the + * data reference; you must use the XPLMGet... and XPLMSet... APIs. With an + * owned data reference, the one owning data reference can manipulate the + * data reference's memory in any way it sees fit. + * + * Shared data references solve two problems: if you need to have a data + * reference used by several plugins but do not know which plugins will be + * installed, or if all plugins sharing data need to be notified when that + * data is changed, use shared data references. + * + */ + + +/* + * XPLMDataChanged_f + * + * An XPLMDataChanged_f is a callback that the XPLM calls whenever any other + * plug-in modifies shared data. A refcon you provide is passed back to help + * identify which data is being changed. In response, you may want to call one + * of the XPLMGetDataxxx routines to find the new value of the data. + * + */ +typedef void (* XPLMDataChanged_f)( + void * inRefcon); + +/* + * XPLMShareData + * + * This routine connects a plug-in to shared data, creating the shared data if + * necessary. inDataName is a standard path for the data ref, and inDataType + * specifies the type. This function will create the data if it does not + * exist. If the data already exists but the type does not match, an error is + * returned, so it is important that plug-in authors collaborate to establish + * public standards for shared data. + * + * If a notificationFunc is passed in and is not NULL, that notification + * function will be called whenever the data is modified. The notification + * refcon will be passed to it. This allows your plug-in to know which shared + * data was changed if multiple shared data are handled by one callback, or if + * the plug-in does not use global variables. + * + * A one is returned for successfully creating or finding the shared data; a + * zero if the data already exists but is of the wrong type. + * + */ +XPLM_API int XPLMShareData( + const char * inDataName, + XPLMDataTypeID inDataType, + XPLMDataChanged_f inNotificationFunc, + void * inNotificationRefcon); + +/* + * XPLMUnshareData + * + * This routine removes your notification function for shared data. Call it + * when done with the data to stop receiving change notifications. Arguments + * must match XPLMShareData. The actual memory will not necessarily be freed, + * since other plug-ins could be using it. + * + */ +XPLM_API int XPLMUnshareData( + const char * inDataName, + XPLMDataTypeID inDataType, + XPLMDataChanged_f inNotificationFunc, + void * inNotificationRefcon); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDefs.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDefs.h new file mode 100644 index 0000000..2e95b81 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDefs.h @@ -0,0 +1,514 @@ +#ifndef _XPLMDefs_h_ +#define _XPLMDefs_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDefs + ***************************************************************************/ +/* + * This file is contains the cross-platform and basic definitions for the + * X-Plane SDK. + * + * The preprocessor macros APL and IBM must be defined to specify the + * compilation target; define APL to 1 and IBM 0 to compile on Macintosh and + * APL to 0 and IBM to 1 for Windows. You must specify these macro definitions + * before including XPLMDefs.h or any other XPLM headers. You can do this + * using the -D command line option or a preprocessor header. + * + */ + + +#ifdef __cplusplus +extern "C" { +#endif + +#if IBM +#include +#else +#include +#endif +/*************************************************************************** + * DLL Definitions + ***************************************************************************/ +/* + * These definitions control the importing and exporting of functions within + * the DLL. + * + * You can prefix your five required callbacks with the PLUGIN_API macro to + * declare them as exported C functions. The XPLM_API macro identifies + * functions that are provided to you via the plugin SDK. (Link against + * XPLM.lib to use these functions.) + * + */ + + +#ifdef __cplusplus + #if APL + #if __GNUC__ >= 4 + #define PLUGIN_API extern "C" __attribute__((visibility("default"))) + #elif __MACH__ + #define PLUGIN_API extern "C" + #else + #define PLUGIN_API extern "C" __declspec(dllexport) + #endif + #elif IBM + #define PLUGIN_API extern "C" __declspec(dllexport) + #elif LIN + #if __GNUC__ >= 4 + #define PLUGIN_API extern "C" __attribute__((visibility("default"))) + #else + #define PLUGIN_API extern "C" + #endif + #else + #error "Platform not defined!" + #endif +#else + #if APL + #if __GNUC__ >= 4 + #define PLUGIN_API __attribute__((visibility("default"))) + #elif __MACH__ + #define PLUGIN_API + #else + #define PLUGIN_API __declspec(dllexport) + #endif + #elif IBM + #define PLUGIN_API __declspec(dllexport) + #elif LIN + #if __GNUC__ >= 4 + #define PLUGIN_API __attribute__((visibility("default"))) + #else + #define PLUGIN_API + #endif + #else + #error "Platform not defined!" + #endif +#endif + +#if APL + #if XPLM + #if __GNUC__ >= 4 + #define XPLM_API __attribute__((visibility("default"))) + #elif __MACH__ + #define XPLM_API + #else + #define XPLM_API __declspec(dllexport) + #endif + #else + #define XPLM_API + #endif +#elif IBM + #if XPLM + #define XPLM_API __declspec(dllexport) + #else + #define XPLM_API __declspec(dllimport) + #endif +#elif LIN + #if XPLM + #if __GNUC__ >= 4 + #define XPLM_API __attribute__((visibility("default"))) + #else + #define XPLM_API + #endif + #else + #define XPLM_API + #endif +#else + #error "Platform not defined!" +#endif + +/*************************************************************************** + * GLOBAL DEFINITIONS + ***************************************************************************/ +/* + * These definitions are used in all parts of the SDK. + * + */ + + +/* + * XPLMPluginID + * + * Each plug-in is identified by a unique integer ID. This ID can be used to + * disable or enable a plug-in, or discover what plug-in is 'running' at the + * time. A plug-in ID is unique within the currently running instance of + * X-Plane unless plug-ins are reloaded. Plug-ins may receive a different + * unique ID each time they are loaded. This includes the unloading and + * reloading of plugins that are part of the user's aircraft. + * + * For persistent identification of plug-ins, use XPLMFindPluginBySignature in + * XPLMUtiltiies.h + * + * -1 indicates no plug-in. + * + */ +typedef int XPLMPluginID; + +/* No plugin. */ +#define XPLM_NO_PLUGIN_ID (-1) + +/* X-Plane itself */ +#define XPLM_PLUGIN_XPLANE (0) + +/* The current XPLM revision is 4.00 (400). */ +#define kXPLM_Version (400) + +/* + * XPLMKeyFlags + * + * These bitfields define modifier keys in a platform independent way. When a + * key is pressed, a series of messages are sent to your plugin. The down + * flag is set in the first of these messages, and the up flag in the last. + * While the key is held down, messages are sent with neither to indicate that + * the key is being held down as a repeated character. + * + * The control flag is mapped to the control flag on Macintosh and PC. + * Generally X-Plane uses the control key and not the command key on + * Macintosh, providing a consistent interface across platforms that does not + * necessarily match the Macintosh user interface guidelines. There is not + * yet a way for plugins to access the Macintosh control keys without using + * #ifdefed code. + * + */ +enum { + /* The shift key is down */ + xplm_ShiftFlag = 1, + + /* The option or alt key is down */ + xplm_OptionAltFlag = 2, + + /* The control key is down* */ + xplm_ControlFlag = 4, + + /* The key is being pressed down */ + xplm_DownFlag = 8, + + /* The key is being released */ + xplm_UpFlag = 16, + + +}; +typedef int XPLMKeyFlags; + +/*************************************************************************** + * ASCII CONTROL KEY CODES + ***************************************************************************/ +/* + * These definitions define how various control keys are mapped to ASCII key + * codes. Not all key presses generate an ASCII value, so plugin code should + * be prepared to see null characters come from the keyboard...this usually + * represents a key stroke that has no equivalent ASCII, like a page-down + * press. Use virtual key codes to find these key strokes. + * + * ASCII key codes take into account modifier keys; shift keys will affect + * capitals and punctuation; control key combinations may have no vaild ASCII + * and produce NULL. To detect control-key combinations, use virtual key + * codes, not ASCII keys. + * + */ + + +#define XPLM_KEY_RETURN 13 + +#define XPLM_KEY_ESCAPE 27 + +#define XPLM_KEY_TAB 9 + +#define XPLM_KEY_DELETE 8 + +#define XPLM_KEY_LEFT 28 + +#define XPLM_KEY_RIGHT 29 + +#define XPLM_KEY_UP 30 + +#define XPLM_KEY_DOWN 31 + +#define XPLM_KEY_0 48 + +#define XPLM_KEY_1 49 + +#define XPLM_KEY_2 50 + +#define XPLM_KEY_3 51 + +#define XPLM_KEY_4 52 + +#define XPLM_KEY_5 53 + +#define XPLM_KEY_6 54 + +#define XPLM_KEY_7 55 + +#define XPLM_KEY_8 56 + +#define XPLM_KEY_9 57 + +#define XPLM_KEY_DECIMAL 46 + +/*************************************************************************** + * VIRTUAL KEY CODES + ***************************************************************************/ +/* + * These are cross-platform defines for every distinct keyboard press on the + * computer. Every physical key on the keyboard has a virtual key code. So + * the "two" key on the top row of the main keyboard has a different code from + * the "two" key on the numeric key pad. But the 'w' and 'W' character are + * indistinguishable by virtual key code because they are the same physical + * key (one with and one without the shift key). + * + * Use virtual key codes to detect keystrokes that do not have ASCII + * equivalents, allow the user to map the numeric keypad separately from the + * main keyboard, and detect control key and other modifier-key combinations + * that generate ASCII control key sequences (many of which are not available + * directly via character keys in the SDK). + * + * To assign virtual key codes we started with the Microsoft set but made some + * additions and changes. A few differences: + * + * 1. Modifier keys are not available as virtual key codes. You cannot get + * distinct modifier press and release messages. Please do not try to use + * modifier keys as regular keys; doing so will almost certainly interfere + * with users' abilities to use the native X-Plane key bindings. + * 2. Some keys that do not exist on both Mac and PC keyboards are removed. + * 3. Do not assume that the values of these keystrokes are interchangeable + * with MS v-keys. + * + */ + + +#define XPLM_VK_BACK 0x08 + +#define XPLM_VK_TAB 0x09 + +#define XPLM_VK_CLEAR 0x0C + +#define XPLM_VK_RETURN 0x0D + +#define XPLM_VK_ESCAPE 0x1B + +#define XPLM_VK_SPACE 0x20 + +#define XPLM_VK_PRIOR 0x21 + +#define XPLM_VK_NEXT 0x22 + +#define XPLM_VK_END 0x23 + +#define XPLM_VK_HOME 0x24 + +#define XPLM_VK_LEFT 0x25 + +#define XPLM_VK_UP 0x26 + +#define XPLM_VK_RIGHT 0x27 + +#define XPLM_VK_DOWN 0x28 + +#define XPLM_VK_SELECT 0x29 + +#define XPLM_VK_PRINT 0x2A + +#define XPLM_VK_EXECUTE 0x2B + +#define XPLM_VK_SNAPSHOT 0x2C + +#define XPLM_VK_INSERT 0x2D + +#define XPLM_VK_DELETE 0x2E + +#define XPLM_VK_HELP 0x2F + +/* XPLM_VK_0 thru XPLM_VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) */ +#define XPLM_VK_0 0x30 + +#define XPLM_VK_1 0x31 + +#define XPLM_VK_2 0x32 + +#define XPLM_VK_3 0x33 + +#define XPLM_VK_4 0x34 + +#define XPLM_VK_5 0x35 + +#define XPLM_VK_6 0x36 + +#define XPLM_VK_7 0x37 + +#define XPLM_VK_8 0x38 + +#define XPLM_VK_9 0x39 + +/* XPLM_VK_A thru XPLM_VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) */ +#define XPLM_VK_A 0x41 + +#define XPLM_VK_B 0x42 + +#define XPLM_VK_C 0x43 + +#define XPLM_VK_D 0x44 + +#define XPLM_VK_E 0x45 + +#define XPLM_VK_F 0x46 + +#define XPLM_VK_G 0x47 + +#define XPLM_VK_H 0x48 + +#define XPLM_VK_I 0x49 + +#define XPLM_VK_J 0x4A + +#define XPLM_VK_K 0x4B + +#define XPLM_VK_L 0x4C + +#define XPLM_VK_M 0x4D + +#define XPLM_VK_N 0x4E + +#define XPLM_VK_O 0x4F + +#define XPLM_VK_P 0x50 + +#define XPLM_VK_Q 0x51 + +#define XPLM_VK_R 0x52 + +#define XPLM_VK_S 0x53 + +#define XPLM_VK_T 0x54 + +#define XPLM_VK_U 0x55 + +#define XPLM_VK_V 0x56 + +#define XPLM_VK_W 0x57 + +#define XPLM_VK_X 0x58 + +#define XPLM_VK_Y 0x59 + +#define XPLM_VK_Z 0x5A + +#define XPLM_VK_NUMPAD0 0x60 + +#define XPLM_VK_NUMPAD1 0x61 + +#define XPLM_VK_NUMPAD2 0x62 + +#define XPLM_VK_NUMPAD3 0x63 + +#define XPLM_VK_NUMPAD4 0x64 + +#define XPLM_VK_NUMPAD5 0x65 + +#define XPLM_VK_NUMPAD6 0x66 + +#define XPLM_VK_NUMPAD7 0x67 + +#define XPLM_VK_NUMPAD8 0x68 + +#define XPLM_VK_NUMPAD9 0x69 + +#define XPLM_VK_MULTIPLY 0x6A + +#define XPLM_VK_ADD 0x6B + +#define XPLM_VK_SEPARATOR 0x6C + +#define XPLM_VK_SUBTRACT 0x6D + +#define XPLM_VK_DECIMAL 0x6E + +#define XPLM_VK_DIVIDE 0x6F + +#define XPLM_VK_F1 0x70 + +#define XPLM_VK_F2 0x71 + +#define XPLM_VK_F3 0x72 + +#define XPLM_VK_F4 0x73 + +#define XPLM_VK_F5 0x74 + +#define XPLM_VK_F6 0x75 + +#define XPLM_VK_F7 0x76 + +#define XPLM_VK_F8 0x77 + +#define XPLM_VK_F9 0x78 + +#define XPLM_VK_F10 0x79 + +#define XPLM_VK_F11 0x7A + +#define XPLM_VK_F12 0x7B + +#define XPLM_VK_F13 0x7C + +#define XPLM_VK_F14 0x7D + +#define XPLM_VK_F15 0x7E + +#define XPLM_VK_F16 0x7F + +#define XPLM_VK_F17 0x80 + +#define XPLM_VK_F18 0x81 + +#define XPLM_VK_F19 0x82 + +#define XPLM_VK_F20 0x83 + +#define XPLM_VK_F21 0x84 + +#define XPLM_VK_F22 0x85 + +#define XPLM_VK_F23 0x86 + +#define XPLM_VK_F24 0x87 + +/* The following definitions are extended and are not based on the Microsoft * + * key set. */ +#define XPLM_VK_EQUAL 0xB0 + +#define XPLM_VK_MINUS 0xB1 + +#define XPLM_VK_RBRACE 0xB2 + +#define XPLM_VK_LBRACE 0xB3 + +#define XPLM_VK_QUOTE 0xB4 + +#define XPLM_VK_SEMICOLON 0xB5 + +#define XPLM_VK_BACKSLASH 0xB6 + +#define XPLM_VK_COMMA 0xB7 + +#define XPLM_VK_SLASH 0xB8 + +#define XPLM_VK_PERIOD 0xB9 + +#define XPLM_VK_BACKQUOTE 0xBA + +#define XPLM_VK_ENTER 0xBB + +#define XPLM_VK_NUMPAD_ENT 0xBC + +#define XPLM_VK_NUMPAD_EQ 0xBD + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDisplay.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDisplay.h new file mode 100644 index 0000000..db5006d --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMDisplay.h @@ -0,0 +1,1658 @@ +#ifndef _XPLMDisplay_h_ +#define _XPLMDisplay_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMDisplay + ***************************************************************************/ +/* + * This API provides the basic hooks to draw in X-Plane and create user + * interface. All X-Plane drawing is done in OpenGL. The X-Plane plug-in + * manager takes care of properly setting up the OpenGL context and matrices. + * You do not decide when in your code's execution to draw; X-Plane tells you + * (via callbacks) when it is ready to have your plugin draw. + * + * X-Plane's drawing strategy is straightforward: every "frame" the screen is + * rendered by drawing the 3-D scene (dome, ground, objects, airplanes, etc.) + * and then drawing the cockpit on top of it. Alpha blending is used to + * overlay the cockpit over the world (and the gauges over the panel, etc.). + * X-Plane user interface elements (including windows like the map, the main + * menu, etc.) are then drawn on top of the cockpit. + * + * There are two ways you can draw: directly and in a window. + * + * Direct drawing (deprecated!---more on that below) involves drawing to the + * screen before or after X-Plane finishes a phase of drawing. When you draw + * directly, you can specify whether X-Plane is to complete this phase or not. + * This allows you to do three things: draw before X-Plane does (under it), + * draw after X-Plane does (over it), or draw instead of X-Plane. + * + * To draw directly, you register a callback and specify which phase you want + * to intercept. The plug-in manager will call you over and over to draw that + * phase. + * + * Direct drawing allows you to override scenery, panels, or anything. Note + * that you cannot assume that you are the only plug-in drawing at this phase. + * + * Direct drawing is deprecated; at some point in the X-Plane 11 run, it will + * likely become unsupported entirely as X-Plane transitions from OpenGL to + * modern graphics API backends (e.g., Vulkan, Metal, etc.). In the long term, + * plugins should use the XPLMInstance API for drawing 3-D objects---this will + * be much more efficient than general 3-D OpenGL drawing, and it will + * actually be supported by the new graphics backends. We do not yet know what + * the post-transition API for generic 3-D drawing will look like (if it + * exists at all). + * + * In contrast to direct drawing, window drawing provides a higher level + * functionality. With window drawing, you create a 2-D window that takes up a + * portion of the screen. Window drawing is always two dimensional. Window + * drawing is front-to-back controlled; you can specify that you want your + * window to be brought on top, and other plug-ins may put their window on top + * of you. Window drawing also allows you to sign up for key presses and + * receive mouse clicks. + * + * Drawing into the screen of an avionics device, like a GPS or a Primary + * Flight Display, is a way to extend or replace X-Plane's avionics. Most + * screens can be displayed both in a 3d cockpit or + * 2d panel, and also in separate popup windows. By installing drawing + * callbacks for a certain avionics device, you can change or extend the + * appearance of that device regardless whether it's installed in a 3d + * cockpit or used in a separate display for home cockpits because you leave + * the window managing to X-Plane. + * + * There are three ways to get keystrokes: + * + * 1. If you create a window, the window can take keyboard focus. It will + * then receive all keystrokes. If no window has focus, X-Plane receives + * keystrokes. Use this to implement typing in dialog boxes, etc. Only + * one window may have focus at a time; your window will be notified if it + * loses focus. + * 2. If you need low level access to the keystroke stream, install a key + * sniffer. Key sniffers can be installed above everything or right in + * front of the sim. + * 3. If you would like to associate key strokes with commands/functions in + * your plug-in, you should simply register a command (via + * XPLMCreateCommand()) and allow users to bind whatever key they choose to + * that command. Another (now deprecated) method of doing so is to use a + * hot key---a key-specific callback. Hotkeys are sent based on virtual + * key strokes, so any key may be distinctly mapped with any modifiers. + * Hot keys can be remapped by other plug-ins. As a plug-in, you don't + * have to worry about what your hot key ends up mapped to; other plug-ins + * may provide a UI for remapping keystrokes. So hotkeys allow a user to + * resolve conflicts and customize keystrokes. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * DRAWING CALLBACKS + ***************************************************************************/ +/* + * Basic drawing callbacks, for low level intercepting of X-Plane's render + * loop. The purpose of drawing callbacks is to provide targeted additions or + * replacements to X-Plane's graphics environment (for example, to add extra + * custom objects, or replace drawing of the AI aircraft). Do not assume that + * the drawing callbacks will be called in the order implied by the + * enumerations. Also do not assume that each drawing phase ends before + * another begins; they may be nested. + * + * Note that all APIs in this section are deprecated, and will likely be + * removed during the X-Plane 11 run as part of the transition to + * Vulkan/Metal/etc. See the XPLMInstance API for future-proof drawing of 3-D + * objects. + * + */ + + +/* + * XPLMDrawingPhase + * + * This constant indicates which part of drawing we are in. Drawing is done + * from the back to the front. We get a callback before or after each item. + * Metaphases provide access to the beginning and end of the 3d (scene) and + * 2d (cockpit) drawing in a manner that is independent of new phases added + * via X-Plane implementation. + * + * **NOTE**: As of XPLM302 the legacy 3D drawing phases (xplm_Phase_FirstScene + * to xplm_Phase_LastScene) are deprecated. When running under X-Plane 11.50 + * with the modern Vulkan or Metal backend, X-Plane will no longer call + * these drawing phases. There is a new drawing phase, xplm_Phase_Modern3D, + * which is supported under OpenGL and Vulkan which is called out roughly + * where the old before xplm_Phase_Airplanes phase was for blending. This + * phase is *NOT* supported under Metal and comes with potentially + * substantial performance overhead. Please do *NOT* opt into this phase if + * you don't do any actual drawing that requires the depth buffer in some + * way! + * + * **WARNING**: As X-Plane's scenery evolves, some drawing phases may cease to + * exist and new ones may be invented. If you need a particularly specific + * use of these codes, consult Austin and/or be prepared to revise your code + * as X-Plane evolves. + * + */ +enum { +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. This is the earliest point at which you can draw * + * in 3-d. */ + xplm_Phase_FirstScene = 0, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing of land and water. */ + xplm_Phase_Terrain = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing runways and other airport detail. */ + xplm_Phase_Airports = 10, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. Drawing roads, trails, trains, etc. */ + xplm_Phase_Vectors = 15, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. 3-d objects (houses, smokestacks, etc. */ + xplm_Phase_Objects = 20, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. External views of airplanes, both yours and the * + * AI aircraft. */ + xplm_Phase_Airplanes = 25, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated as of XPLM302. This is the last point at which you can draw in * + * 3-d. */ + xplm_Phase_LastScene = 30, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM302) + /* A chance to do modern 3D drawing. */ + xplm_Phase_Modern3D = 31, + +#endif /* XPLM302 */ + /* This is the first phase where you can draw in 2-d. */ + xplm_Phase_FirstCockpit = 35, + + /* The non-moving parts of the aircraft panel. */ + xplm_Phase_Panel = 40, + + /* The moving parts of the aircraft panel. */ + xplm_Phase_Gauges = 45, + + /* Floating windows from plugins. */ + xplm_Phase_Window = 50, + + /* The last chance to draw in 2d. */ + xplm_Phase_LastCockpit = 55, + +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMap3D = 100, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMap2D = 101, + +#endif /* XPLM200 */ +#if defined(XPLM200) + /* Removed as of XPLM300; Use the full-blown XPLMMap API instead. */ + xplm_Phase_LocalMapProfile = 102, + +#endif /* XPLM200 */ + +}; +typedef int XPLMDrawingPhase; + +/* + * XPLMDrawCallback_f + * + * This is the prototype for a low level drawing callback. You are passed in + * the phase and whether it is before or after. If you are before the phase, + * return 1 to let X-Plane draw or 0 to suppress X-Plane drawing. If you are + * after the phase the return value is ignored. + * + * Refcon is a unique value that you specify when registering the callback, + * allowing you to slip a pointer to your own data to the callback. + * + * Upon entry the OpenGL context will be correctly set up for you and OpenGL + * will be in 'local' coordinates for 3d drawing and panel coordinates for 2d + * drawing. The OpenGL state (texturing, etc.) will be unknown. + * + */ +typedef int (* XPLMDrawCallback_f)( + XPLMDrawingPhase inPhase, + int inIsBefore, + void * inRefcon); + +/* + * XPLMRegisterDrawCallback + * + * This routine registers a low level drawing callback. Pass in the phase you + * want to be called for and whether you want to be called before or after. + * This routine returns 1 if the registration was successful, or 0 if the + * phase does not exist in this version of X-Plane. You may register a + * callback multiple times for the same or different phases as long as the + * refcon is unique each time. + * + * Note that this function will likely be removed during the X-Plane 11 run as + * part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + * future-proof drawing of 3-D objects. + * + */ +XPLM_API int XPLMRegisterDrawCallback( + XPLMDrawCallback_f inCallback, + XPLMDrawingPhase inPhase, + int inWantsBefore, + void * inRefcon); + +/* + * XPLMUnregisterDrawCallback + * + * This routine unregisters a draw callback. You must unregister a callback + * for each time you register a callback if you have registered it multiple + * times with different refcons. The routine returns 1 if it can find the + * callback to unregister, 0 otherwise. + * + * Note that this function will likely be removed during the X-Plane 11 run as + * part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + * future-proof drawing of 3-D objects. + * + */ +XPLM_API int XPLMUnregisterDrawCallback( + XPLMDrawCallback_f inCallback, + XPLMDrawingPhase inPhase, + int inWantsBefore, + void * inRefcon); + +#if defined(XPLM400) +/*************************************************************************** + * AVIONICS API + ***************************************************************************/ +/* + * Drawing callbacks for before and after X-Plane draws the instrument screen + * can be registered for every cockpit device. If the user plane does not + * have the device installed, your callback will not be called! Use the + * return value to enable or disable X-Plane's drawing. By drawing into the + * framebuffer of the avionics device, your modifications will be visible + * regardless whether the device's screen is in a 3d cockpit or a popup + * window. + * + */ + + +/* + * XPLMDeviceID + * + * This constant indicates the device we want to override or enhance. We can + * get a callback before or after each item. + * + */ +enum { + /* GNS430, pilot side. */ + xplm_device_GNS430_1 = 0, + + /* GNS430, copilot side. */ + xplm_device_GNS430_2 = 1, + + /* GNS530, pilot side. */ + xplm_device_GNS530_1 = 2, + + /* GNS530, copilot side. */ + xplm_device_GNS530_2 = 3, + + /* generic airliner CDU, pilot side. */ + xplm_device_CDU739_1 = 4, + + /* generic airliner CDU, copilot side. */ + xplm_device_CDU739_2 = 5, + + /* G1000 Primary Flight Display, pilot side. */ + xplm_device_G1000_PFD_1 = 6, + + /* G1000 Multifunction Display. */ + xplm_device_G1000_MFD = 7, + + /* G1000 Primary Flight Display, copilot side. */ + xplm_device_G1000_PFD_2 = 8, + + /* Primus CDU, pilot side. */ + xplm_device_CDU815_1 = 9, + + /* Primus CDU, copilot side. */ + xplm_device_CDU815_2 = 10, + + /* Primus Primary Flight Display, pilot side. */ + xplm_device_Primus_PFD_1 = 11, + + /* Primus Primary Flight Display, copilot side. */ + xplm_device_Primus_PFD_2 = 12, + + /* Primus Multifunction Display, pilot side. */ + xplm_device_Primus_MFD_1 = 13, + + /* Primus Multifunction Display, copilot side. */ + xplm_device_Primus_MFD_2 = 14, + + /* Primus Multifunction Display, central. */ + xplm_device_Primus_MFD_3 = 15, + + /* Primus Radio Management Unit, pilot side. */ + xplm_device_Primus_RMU_1 = 16, + + /* Primus Radio Management Unit, copilot side. */ + xplm_device_Primus_RMU_2 = 17, + + +}; +typedef int XPLMDeviceID; + +/* + * XPLMAvionicsCallback_f + * + * This is the prototype for your drawing callback. You are passed in the + * device you are enhancing/replacing, and whether it is before or after + * X-Plane drawing. If you are before X-Plane, return 1 to let X-Plane draw or + * 0 to suppress X-Plane drawing. If you are after the phase the return value + * is ignored. + * + * Refcon is a unique value that you specify when registering the callback, + * allowing you to slip a pointer to your own data to the callback. + * + * Upon entry the OpenGL context will be correctly set up for you and OpenGL + * will be in panel coordinates for 2d drawing. The OpenGL state (texturing, + * etc.) will be unknown. + * + */ +typedef int (* XPLMAvionicsCallback_f)( + XPLMDeviceID inDeviceID, + int inIsBefore, + void * inRefcon); + +/* + * XPLMAvionicsID + * + * This is an opaque identifier for an avionics display that you enhance or + * replace. When you register your callbacks (via + * XPLMRegisterAvionicsCallbacksEx()), you will specify callbacks to handle + * drawing, and get back such a handle. + * + */ +typedef void * XPLMAvionicsID; + +/* + * XPLMCustomizeAvionics_t + * + * The XPLMCustomizeAvionics_t structure defines all of the parameters used to + * replace or enhance avionics for using XPLMRegisterAvionicsCallbacksEx(). + * The structure will be expanded in future SDK APIs to include more features. + * Always set the structSize member to the size of your struct in bytes! + * + */ +typedef struct { + /* Used to inform XPLMRegisterAvionicsCallbacksEx() of the SDK version you * + * compiled against; should always be set to sizeof(XPLMCustomizeAvionics_t) */ + int structSize; + /* Which avionics device you want your drawing applied to. */ + XPLMDeviceID deviceId; + /* The draw callback to be called before X-Plane draws. */ + XPLMAvionicsCallback_f drawCallbackBefore; + /* The draw callback to be called after X-Plane has drawn. */ + XPLMAvionicsCallback_f drawCallbackAfter; + /* A reference which will be passed into each of your draw callbacks. Use this* + * to pass information to yourself as needed. */ + void * refcon; +} XPLMCustomizeAvionics_t; + +/* + * XPLMRegisterAvionicsCallbacksEx + * + * This routine registers your callbacks for a device. This returns a handle. + * If the returned handle is NULL, there was a problem interpreting your + * input, most likely the struct size was wrong for your SDK version. If the + * returned handle is not NULL, your callbacks will be called according to + * schedule as long as your plugin is not deactivated, or unloaded, or your + * call XPLMUnregisterAvionicsCallbacks(). + * + */ +XPLM_API XPLMAvionicsID XPLMRegisterAvionicsCallbacksEx( + XPLMCustomizeAvionics_t * inParams); + +/* + * XPLMUnregisterAvionicsCallbacks + * + * This routine unregisters your callbacks for a device. They will no longer + * be called. + * + */ +XPLM_API void XPLMUnregisterAvionicsCallbacks( + XPLMAvionicsID inAvionicsId); + +#endif /* XPLM400 */ +/*************************************************************************** + * WINDOW API + ***************************************************************************/ +/* + * The window API provides a high-level abstraction for drawing with UI + * interaction. + * + * Windows may operate in one of two modes: legacy (for plugins compiled + * against old versions of the XPLM, as well as windows created via the + * deprecated XPLMCreateWindow() function, rather than XPLMCreateWindowEx()), + * or modern (for windows compiled against the XPLM300 or newer API, and + * created via XPLMCreateWindowEx()). + * + * Modern windows have access to new X-Plane 11 windowing features, like + * support for new positioning modes (including being "popped out" into their + * own first-class window in the operating system). They can also optionally + * be decorated in the style of X-Plane 11 windows (like the map). + * + * Modern windows operate in "boxel" units. A boxel ("box of pixels") is a + * unit of virtual pixels which, depending on X-Plane's scaling, may + * correspond to an arbitrary NxN "box" of real pixels on screen. Because + * X-Plane handles this scaling automatically, you can effectively treat the + * units as though you were simply drawing in pixels, and know that when + * X-Plane is running with 150% or 200% scaling, your drawing will be + * automatically scaled (and likewise all mouse coordinates, screen bounds, + * etc. will also be auto-scaled). + * + * In contrast, legacy windows draw in true screen pixels, and thus tend to + * look quite small when X-Plane is operating in a scaled mode. + * + * Legacy windows have their origin in the lower left of the main X-Plane + * window. In contrast, since modern windows are not constrained to the main + * window, they have their origin in the lower left of the entire global + * desktop space, and the lower left of the main X-Plane window is not + * guaranteed to be (0, 0). In both cases, x increases as you move left, and y + * increases as you move up. + * + */ + + +/* + * XPLMWindowID + * + * This is an opaque identifier for a window. You use it to control your + * window. When you create a window (via either XPLMCreateWindow() or + * XPLMCreateWindowEx()), you will specify callbacks to handle drawing, mouse + * interaction, etc. + * + */ +typedef void * XPLMWindowID; + +/* + * XPLMDrawWindow_f + * + * A callback to handle 2-D drawing of your window. You are passed in your + * window and its refcon. Draw the window. You can use other XPLM functions + * from this header to find the current dimensions of your window, etc. When + * this callback is called, the OpenGL context will be set properly for 2-D + * window drawing. + * + * **Note**: Because you are drawing your window over a background, you can + * make a translucent window easily by simply not filling in your entire + * window's bounds. + * + */ +typedef void (* XPLMDrawWindow_f)( + XPLMWindowID inWindowID, + void * inRefcon); + +/* + * XPLMHandleKey_f + * + * This function is called when a key is pressed or keyboard focus is taken + * away from your window. If losingFocus is 1, you are losing the keyboard + * focus, otherwise a key was pressed and inKey contains its character. + * + * The window ID passed in will be your window for key presses, or the other + * window taking focus when losing focus. Note that in the modern plugin + * system, often focus is taken by the window manager itself; for this resaon, + * the window ID may be zero when losing focus, and you should not write code + * that depends onit. + * + * The refcon passed in will be the one from registration, for both key + * presses and losing focus. + * + * Warning: this API declares virtual keys as a signed character; however the + * VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + * (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + * to an unsigned char to get correct comparisons in C. + * + */ +typedef void (* XPLMHandleKey_f)( + XPLMWindowID inWindowID, + char inKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefcon, + int losingFocus); + +/* + * XPLMMouseStatus + * + * When the mouse is clicked, your mouse click routine is called repeatedly. + * It is first called with the mouse down message. It is then called zero or + * more times with the mouse-drag message, and finally it is called once with + * the mouse up message. All of these messages will be directed to the same + * window; you are guaranteed to not receive a drag or mouse-up event without + * first receiving the corresponding mouse-down. + * + */ +enum { + xplm_MouseDown = 1, + + xplm_MouseDrag = 2, + + xplm_MouseUp = 3, + + +}; +typedef int XPLMMouseStatus; + +/* + * XPLMHandleMouseClick_f + * + * You receive this call for one of three events: + * + * - when the user clicks the mouse button down + * - (optionally) when the user drags the mouse after a down-click, but before + * the up-click + * - when the user releases the down-clicked mouse button. + * + * You receive the x and y of the click, your window, and a refcon. Return 1 + * to consume the click, or 0 to pass it through. + * + * WARNING: passing clicks through windows (as of this writing) causes mouse + * tracking problems in X-Plane; do not use this feature! + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef int (* XPLMHandleMouseClick_f)( + XPLMWindowID inWindowID, + int x, + int y, + XPLMMouseStatus inMouse, + void * inRefcon); + +#if defined(XPLM200) +/* + * XPLMCursorStatus + * + * XPLMCursorStatus describes how you would like X-Plane to manage the cursor. + * See XPLMHandleCursor_f for more info. + * + */ +enum { + /* X-Plane manages the cursor normally, plugin does not affect the cusrsor. */ + xplm_CursorDefault = 0, + + /* X-Plane hides the cursor. */ + xplm_CursorHidden = 1, + + /* X-Plane shows the cursor as the default arrow. */ + xplm_CursorArrow = 2, + + /* X-Plane shows the cursor but lets you select an OS cursor. */ + xplm_CursorCustom = 3, + + +}; +typedef int XPLMCursorStatus; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMHandleCursor_f + * + * The SDK calls your cursor status callback when the mouse is over your + * plugin window. Return a cursor status code to indicate how you would like + * X-Plane to manage the cursor. If you return xplm_CursorDefault, the SDK + * will try lower-Z-order plugin windows, then let the sim manage the cursor. + * + * Note: you should never show or hide the cursor yourself---these APIs are + * typically reference-counted and thus cannot safely and predictably be used + * by the SDK. Instead return one of xplm_CursorHidden to hide the cursor or + * xplm_CursorArrow/xplm_CursorCustom to show the cursor. + * + * If you want to implement a custom cursor by drawing a cursor in OpenGL, use + * xplm_CursorHidden to hide the OS cursor and draw the cursor using a 2-d + * drawing callback (after xplm_Phase_Window is probably a good choice, but + * see deprecation warnings on the drawing APIs!). If you want to use a + * custom OS-based cursor, use xplm_CursorCustom to ask X-Plane to show the + * cursor but not affect its image. You can then use an OS specific call like + * SetThemeCursor (Mac) or SetCursor/LoadCursor (Windows). + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef XPLMCursorStatus (* XPLMHandleCursor_f)( + XPLMWindowID inWindowID, + int x, + int y, + void * inRefcon); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMHandleMouseWheel_f + * + * The SDK calls your mouse wheel callback when one of the mouse wheels is + * scrolled within your window. Return 1 to consume the mouse wheel movement + * or 0 to pass them on to a lower window. (If your window appears opaque to + * the user, you should consume mouse wheel scrolling even if it does + * nothing.) The number of "clicks" indicates how far the wheel was turned + * since the last callback. The wheel is 0 for the vertical axis or 1 for the + * horizontal axis (for OS/mouse combinations that support this). + * + * The units for x and y values match the units used in your window. Thus, for + * "modern" windows (those created via XPLMCreateWindowEx() and compiled + * against the XPLM300 library), the units are boxels, while legacy windows + * will get pixels. Legacy windows have their origin in the lower left of the + * main X-Plane window, while modern windows have their origin in the lower + * left of the global desktop space. In both cases, x increases as you move + * right, and y increases as you move up. + * + */ +typedef int (* XPLMHandleMouseWheel_f)( + XPLMWindowID inWindowID, + int x, + int y, + int wheel, + int clicks, + void * inRefcon); +#endif /* XPLM200 */ + +#if defined(XPLM300) +/* + * XPLMWindowLayer + * + * XPLMWindowLayer describes where in the ordering of windows X-Plane should + * place a particular window. Windows in higher layers cover windows in lower + * layers. So, a given window might be at the top of its particular layer, but + * it might still be obscured by a window in a higher layer. (This happens + * frequently when floating windows, like X-Plane's map, are covered by a + * modal alert.) + * + * Your window's layer can only be specified when you create the window (in + * the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). For this reason, + * layering only applies to windows created with new X-Plane 11 GUI features. + * (Windows created using the older XPLMCreateWindow(), or windows compiled + * against a pre-XPLM300 version of the SDK will simply be placed in the + * flight overlay window layer.) + * + */ +enum { + /* The lowest layer, used for HUD-like displays while flying. */ + xplm_WindowLayerFlightOverlay = 0, + + /* Windows that "float" over the sim, like the X-Plane 11 map does. If you are* + * not sure which layer to create your window in, choose floating. */ + xplm_WindowLayerFloatingWindows = 1, + + /* An interruptive modal that covers the sim with a transparent black overlay * + * to draw the user's focus to the alert */ + xplm_WindowLayerModal = 2, + + /* "Growl"-style notifications that are visible in a corner of the screen, * + * even over modals */ + xplm_WindowLayerGrowlNotifications = 3, + + +}; +typedef int XPLMWindowLayer; +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMWindowDecoration + * + * XPLMWindowDecoration describes how "modern" windows will be displayed. This + * impacts both how X-Plane draws your window as well as certain mouse + * handlers. + * + * Your window's decoration can only be specified when you create the window + * (in the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). + * + */ +enum { + /* X-Plane will draw no decoration for your window, and apply no automatic * + * click handlers. The window will not stop click from passing through its * + * bounds. This is suitable for "windows" which request, say, the full screen * + * bounds, then only draw in a small portion of the available area. */ + xplm_WindowDecorationNone = 0, + + /* The default decoration for "native" windows, like the map. Provides a solid* + * background, as well as click handlers for resizing and dragging the window.*/ + xplm_WindowDecorationRoundRectangle = 1, + + /* X-Plane will draw no decoration for your window, nor will it provide resize* + * handlers for your window edges, but it will stop clicks from passing * + * through your windows bounds. */ + xplm_WindowDecorationSelfDecorated = 2, + + /* Like self-decorated, but with resizing; X-Plane will draw no decoration for* + * your window, but it will stop clicks from passing through your windows * + * bounds, and provide automatic mouse handlers for resizing. */ + xplm_WindowDecorationSelfDecoratedResizable = 3, + + +}; +typedef int XPLMWindowDecoration; +#endif /* XPLM301 */ + +#if defined(XPLM200) +/* + * XPLMCreateWindow_t + * + * The XPMCreateWindow_t structure defines all of the parameters used to + * create a modern window using XPLMCreateWindowEx(). The structure will be + * expanded in future SDK APIs to include more features. Always set the + * structSize member to the size of your struct in bytes! + * + * All windows created by this function in the XPLM300 version of the API are + * created with the new X-Plane 11 GUI features. This means your plugin will + * get to "know" about the existence of X-Plane windows other than the main + * window. All drawing and mouse callbacks for your window will occur in + * "boxels," giving your windows automatic support for high-DPI scaling in + * X-Plane. In addition, your windows can opt-in to decoration with the + * X-Plane 11 window styling, and you can use the + * XPLMSetWindowPositioningMode() API to make your window "popped out" into a + * first-class operating system window. + * + * Note that this requires dealing with your window's bounds in "global + * desktop" positioning units, rather than the traditional panel coordinate + * system. In global desktop coordinates, the main X-Plane window may not have + * its origin at coordinate (0, 0), and your own window may have negative + * coordinates. Assuming you don't implicitly assume (0, 0) as your origin, + * the only API change you should need is to start using + * XPLMGetMouseLocationGlobal() rather than XPLMGetMouseLocation(), and + * XPLMGetScreenBoundsGlobal() instead of XPLMGetScreenSize(). + * + * If you ask to be decorated as a floating window, you'll get the blue window + * control bar and blue backing that you see in X-Plane 11's normal "floating" + * windows (like the map). + * + */ +typedef struct { + /* Used to inform XPLMCreateWindowEx() of the SDK version you compiled * + * against; should always be set to sizeof(XPLMCreateWindow_t) */ + int structSize; + /* Left bound, in global desktop boxels */ + int left; + /* Top bound, in global desktop boxels */ + int top; + /* Right bound, in global desktop boxels */ + int right; + /* Bottom bound, in global desktop boxels */ + int bottom; + int visible; + XPLMDrawWindow_f drawWindowFunc; + /* A callback to handle the user left-clicking within your window (or NULL to * + * ignore left clicks) */ + XPLMHandleMouseClick_f handleMouseClickFunc; + XPLMHandleKey_f handleKeyFunc; + XPLMHandleCursor_f handleCursorFunc; + XPLMHandleMouseWheel_f handleMouseWheelFunc; + /* A reference which will be passed into each of your window callbacks. Use * + * this to pass information to yourself as needed. */ + void * refcon; +#if defined(XPLM301) + /* Specifies the type of X-Plane 11-style "wrapper" you want around your * + * window, if any */ + XPLMWindowDecoration decorateAsFloatingWindow; +#endif /* XPLM301 */ +#if defined(XPLM300) + XPLMWindowLayer layer; +#endif /* XPLM300 */ +#if defined(XPLM300) + /* A callback to handle the user right-clicking within your window (or NULL to* + * ignore right clicks) */ + XPLMHandleMouseClick_f handleRightClickFunc; +#endif /* XPLM300 */ +} XPLMCreateWindow_t; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMCreateWindowEx + * + * This routine creates a new "modern" window. You pass in an + * XPLMCreateWindow_t structure with all of the fields set in. You must set + * the structSize of the structure to the size of the actual structure you + * used. Also, you must provide functions for every callback---you may not + * leave them null! (If you do not support the cursor or mouse wheel, use + * functions that return the default values.) + * + */ +XPLM_API XPLMWindowID XPLMCreateWindowEx( + XPLMCreateWindow_t * inParams); +#endif /* XPLM200 */ + +/* + * XPLMCreateWindow + * + * Deprecated as of XPLM300. + * + * This routine creates a new legacy window. Unlike modern windows (created + * via XPLMCreateWindowEx()), legacy windows do not have access to X-Plane 11 + * features like automatic scaling for high-DPI screens, native window styles, + * or support for being "popped out" into first-class operating system + * windows. + * + * Pass in the dimensions and offsets to the window's bottom left corner from + * the bottom left of the screen. You can specify whether the window is + * initially visible or not. Also, you pass in three callbacks to run the + * window and a refcon. This function returns a window ID you can use to + * refer to the new window. + * + * NOTE: Legacy windows do not have "frames"; you are responsible for drawing + * the background and frame of the window. Higher level libraries have + * routines which make this easy. + * + */ +XPLM_API XPLMWindowID XPLMCreateWindow( + int inLeft, + int inTop, + int inRight, + int inBottom, + int inIsVisible, + XPLMDrawWindow_f inDrawCallback, + XPLMHandleKey_f inKeyCallback, + XPLMHandleMouseClick_f inMouseCallback, + void * inRefcon); + +/* + * XPLMDestroyWindow + * + * This routine destroys a window. The window's callbacks are not called + * after this call. Keyboard focus is removed from the window before + * destroying it. + * + */ +XPLM_API void XPLMDestroyWindow( + XPLMWindowID inWindowID); + +/* + * XPLMGetScreenSize + * + * This routine returns the size of the main X-Plane OpenGL window in pixels. + * This number can be used to get a rough idea of the amount of detail the + * user will be able to see when drawing in 3-d. + * + */ +XPLM_API void XPLMGetScreenSize( + int * outWidth, /* Can be NULL */ + int * outHeight); /* Can be NULL */ + +#if defined(XPLM300) +/* + * XPLMGetScreenBoundsGlobal + * + * This routine returns the bounds of the "global" X-Plane desktop, in boxels. + * Unlike the non-global version XPLMGetScreenSize(), this is multi-monitor + * aware. There are three primary consequences of multimonitor awareness. + * + * First, if the user is running X-Plane in full-screen on two or more + * monitors (typically configured using one full-screen window per monitor), + * the global desktop will be sized to include all X-Plane windows. + * + * Second, the origin of the screen coordinates is not guaranteed to be (0, + * 0). Suppose the user has two displays side-by-side, both running at 1080p. + * Suppose further that they've configured their OS to make the left display + * their "primary" monitor, and that X-Plane is running in full-screen on + * their right monitor only. In this case, the global desktop bounds would be + * the rectangle from (1920, 0) to (3840, 1080). If the user later asked + * X-Plane to draw on their primary monitor as well, the bounds would change + * to (0, 0) to (3840, 1080). + * + * Finally, if the usable area of the virtual desktop is not a perfect + * rectangle (for instance, because the monitors have different resolutions or + * because one monitor is configured in the operating system to be above and + * to the right of the other), the global desktop will include any wasted + * space. Thus, if you have two 1080p monitors, and monitor 2 is configured to + * have its bottom left touch monitor 1's upper right, your global desktop + * area would be the rectangle from (0, 0) to (3840, 2160). + * + * Note that popped-out windows (windows drawn in their own operating system + * windows, rather than "floating" within X-Plane) are not included in these + * bounds. + * + */ +XPLM_API void XPLMGetScreenBoundsGlobal( + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMReceiveMonitorBoundsGlobal_f + * + * This function is informed of the global bounds (in boxels) of a particular + * monitor within the X-Plane global desktop space. Note that X-Plane must be + * running in full screen on a monitor in order for that monitor to be passed + * to you in this callback. + * + */ +typedef void (* XPLMReceiveMonitorBoundsGlobal_f)( + int inMonitorIndex, + int inLeftBx, + int inTopBx, + int inRightBx, + int inBottomBx, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMGetAllMonitorBoundsGlobal + * + * This routine immediately calls you back with the bounds (in boxels) of each + * full-screen X-Plane window within the X-Plane global desktop space. Note + * that if a monitor is *not* covered by an X-Plane window, you cannot get its + * bounds this way. Likewise, monitors with only an X-Plane window (not in + * full-screen mode) will not be included. + * + * If X-Plane is running in full-screen and your monitors are of the same size + * and configured contiguously in the OS, then the combined global bounds of + * all full-screen monitors will match the total global desktop bounds, as + * returned by XPLMGetScreenBoundsGlobal(). (Of course, if X-Plane is running + * in windowed mode, this will not be the case. Likewise, if you have + * differently sized monitors, the global desktop space will include wasted + * space.) + * + * Note that this function's monitor indices match those provided by + * XPLMGetAllMonitorBoundsOS(), but the coordinates are different (since the + * X-Plane global desktop may not match the operating system's global desktop, + * and one X-Plane boxel may be larger than one pixel due to 150% or 200% + * scaling). + * + */ +XPLM_API void XPLMGetAllMonitorBoundsGlobal( + XPLMReceiveMonitorBoundsGlobal_f inMonitorBoundsCallback, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMReceiveMonitorBoundsOS_f + * + * This function is informed of the global bounds (in pixels) of a particular + * monitor within the operating system's global desktop space. Note that a + * monitor index being passed to you here does not indicate that X-Plane is + * running in full screen on this monitor, or even that any X-Plane windows + * exist on this monitor. + * + */ +typedef void (* XPLMReceiveMonitorBoundsOS_f)( + int inMonitorIndex, + int inLeftPx, + int inTopPx, + int inRightPx, + int inBottomPx, + void * inRefcon); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMGetAllMonitorBoundsOS + * + * This routine immediately calls you back with the bounds (in pixels) of each + * monitor within the operating system's global desktop space. Note that + * unlike XPLMGetAllMonitorBoundsGlobal(), this may include monitors that have + * no X-Plane window on them. + * + * Note that this function's monitor indices match those provided by + * XPLMGetAllMonitorBoundsGlobal(), but the coordinates are different (since + * the X-Plane global desktop may not match the operating system's global + * desktop, and one X-Plane boxel may be larger than one pixel). + * + */ +XPLM_API void XPLMGetAllMonitorBoundsOS( + XPLMReceiveMonitorBoundsOS_f inMonitorBoundsCallback, + void * inRefcon); +#endif /* XPLM300 */ + +/* + * XPLMGetMouseLocation + * + * Deprecated in XPLM300. Modern windows should use + * XPLMGetMouseLocationGlobal() instead. + * + * This routine returns the current mouse location in pixels relative to the + * main X-Plane window. The bottom left corner of the main window is (0, 0). + * Pass NULL to not receive info about either parameter. + * + * Because this function gives the mouse position relative to the main X-Plane + * window (rather than in global bounds), this function should only be used by + * legacy windows. Modern windows should instead get the mouse position in + * global desktop coordinates using XPLMGetMouseLocationGlobal(). + * + * Note that unlike XPLMGetMouseLocationGlobal(), if the mouse goes outside + * the user's main monitor (for instance, to a pop out window or a secondary + * monitor), this function will not reflect it. + * + */ +XPLM_API void XPLMGetMouseLocation( + int * outX, /* Can be NULL */ + int * outY); /* Can be NULL */ + +#if defined(XPLM300) +/* + * XPLMGetMouseLocationGlobal + * + * Returns the current mouse location in global desktop boxels. Unlike + * XPLMGetMouseLocation(), the bottom left of the main X-Plane window is not + * guaranteed to be (0, 0)---instead, the origin is the lower left of the + * entire global desktop space. In addition, this routine gives the real mouse + * location when the mouse goes to X-Plane windows other than the primary + * display. Thus, it can be used with both pop-out windows and secondary + * monitors. + * + * This is the mouse location function to use with modern windows (i.e., those + * created by XPLMCreateWindowEx()). + * + * Pass NULL to not receive info about either parameter. + * + */ +XPLM_API void XPLMGetMouseLocationGlobal( + int * outX, /* Can be NULL */ + int * outY); /* Can be NULL */ +#endif /* XPLM300 */ + +/* + * XPLMGetWindowGeometry + * + * This routine returns the position and size of a window. The units and + * coordinate system vary depending on the type of window you have. + * + * If this is a legacy window (one compiled against a pre-XPLM300 version of + * the SDK, or an XPLM300 window that was not created using + * XPLMCreateWindowEx()), the units are pixels relative to the main X-Plane + * display. + * + * If, on the other hand, this is a new X-Plane 11-style window (compiled + * against the XPLM300 SDK and created using XPLMCreateWindowEx()), the units + * are global desktop boxels. + * + * Pass NULL to not receive any paramter. + * + */ +XPLM_API void XPLMGetWindowGeometry( + XPLMWindowID inWindowID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ + +/* + * XPLMSetWindowGeometry + * + * This routine allows you to set the position and size of a window. + * + * The units and coordinate system match those of XPLMGetWindowGeometry(). + * That is, modern windows use global desktop boxel coordinates, while legacy + * windows use pixels relative to the main X-Plane display. + * + * Note that this only applies to "floating" windows (that is, windows that + * are drawn within the X-Plane simulation windows, rather than being "popped + * out" into their own first-class operating system windows). To set the + * position of windows whose positioning mode is xplm_WindowPopOut, you'll + * need to instead use XPLMSetWindowGeometryOS(). + * + */ +XPLM_API void XPLMSetWindowGeometry( + XPLMWindowID inWindowID, + int inLeft, + int inTop, + int inRight, + int inBottom); + +#if defined(XPLM300) +/* + * XPLMGetWindowGeometryOS + * + * This routine returns the position and size of a "popped out" window (i.e., + * a window whose positioning mode is xplm_WindowPopOut), in operating system + * pixels. Pass NULL to not receive any parameter. + * + */ +XPLM_API void XPLMGetWindowGeometryOS( + XPLMWindowID inWindowID, + int * outLeft, /* Can be NULL */ + int * outTop, /* Can be NULL */ + int * outRight, /* Can be NULL */ + int * outBottom); /* Can be NULL */ +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowGeometryOS + * + * This routine allows you to set the position and size, in operating system + * pixel coordinates, of a popped out window (that is, a window whose + * positioning mode is xplm_WindowPopOut, which exists outside the X-Plane + * simulation window, in its own first-class operating system window). + * + * Note that you are responsible for ensuring both that your window is popped + * out (using XPLMWindowIsPoppedOut()) and that a monitor really exists at the + * OS coordinates you provide (using XPLMGetAllMonitorBoundsOS()). + * + */ +XPLM_API void XPLMSetWindowGeometryOS( + XPLMWindowID inWindowID, + int inLeft, + int inTop, + int inRight, + int inBottom); +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMGetWindowGeometryVR + * + * Returns the width and height, in boxels, of a window in VR. Note that you + * are responsible for ensuring your window is in VR (using + * XPLMWindowIsInVR()). + * + */ +XPLM_API void XPLMGetWindowGeometryVR( + XPLMWindowID inWindowID, + int * outWidthBoxels, /* Can be NULL */ + int * outHeightBoxels); /* Can be NULL */ +#endif /* XPLM301 */ + +#if defined(XPLM301) +/* + * XPLMSetWindowGeometryVR + * + * This routine allows you to set the size, in boxels, of a window in VR (that + * is, a window whose positioning mode is xplm_WindowVR). + * + * Note that you are responsible for ensuring your window is in VR (using + * XPLMWindowIsInVR()). + * + */ +XPLM_API void XPLMSetWindowGeometryVR( + XPLMWindowID inWindowID, + int widthBoxels, + int heightBoxels); +#endif /* XPLM301 */ + +/* + * XPLMGetWindowIsVisible + * + * Returns true (1) if the specified window is visible. + * + */ +XPLM_API int XPLMGetWindowIsVisible( + XPLMWindowID inWindowID); + +/* + * XPLMSetWindowIsVisible + * + * This routine shows or hides a window. + * + */ +XPLM_API void XPLMSetWindowIsVisible( + XPLMWindowID inWindowID, + int inIsVisible); + +#if defined(XPLM300) +/* + * XPLMWindowIsPoppedOut + * + * True if this window has been popped out (making it a first-class window in + * the operating system), which in turn is true if and only if you have set + * the window's positioning mode to xplm_WindowPopOut. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK cannot be popped out.) + * + */ +XPLM_API int XPLMWindowIsPoppedOut( + XPLMWindowID inWindowID); +#endif /* XPLM300 */ + +#if defined(XPLM301) +/* + * XPLMWindowIsInVR + * + * True if this window has been moved to the virtual reality (VR) headset, + * which in turn is true if and only if you have set the window's positioning + * mode to xplm_WindowVR. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM301 version of + * the SDK cannot be moved to VR.) + * + */ +XPLM_API int XPLMWindowIsInVR( + XPLMWindowID inWindowID); +#endif /* XPLM301 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowGravity + * + * A window's "gravity" controls how the window shifts as the whole X-Plane + * window resizes. A gravity of 1 means the window maintains its positioning + * relative to the right or top edges, 0 the left/bottom, and 0.5 keeps it + * centered. + * + * Default gravity is (0, 1, 0, 1), meaning your window will maintain its + * position relative to the top left and will not change size as its + * containing window grows. + * + * If you wanted, say, a window that sticks to the top of the screen (with a + * constant height), but which grows to take the full width of the window, you + * would pass (0, 1, 1, 1). Because your left and right edges would maintain + * their positioning relative to their respective edges of the screen, the + * whole width of your window would change with the X-Plane window. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will simply get the default gravity.) + * + */ +XPLM_API void XPLMSetWindowGravity( + XPLMWindowID inWindowID, + float inLeftGravity, + float inTopGravity, + float inRightGravity, + float inBottomGravity); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowResizingLimits + * + * Sets the minimum and maximum size of the client rectangle of the given + * window. (That is, it does not include any window styling that you might + * have asked X-Plane to apply on your behalf.) All resizing operations are + * constrained to these sizes. + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will have no minimum or maximum size.) + * + */ +XPLM_API void XPLMSetWindowResizingLimits( + XPLMWindowID inWindowID, + int inMinWidthBoxels, + int inMinHeightBoxels, + int inMaxWidthBoxels, + int inMaxHeightBoxels); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMWindowPositioningMode + * + * XPLMWindowPositionMode describes how X-Plane will position your window on + * the user's screen. X-Plane will maintain this positioning mode even as the + * user resizes their window or adds/removes full-screen monitors. + * + * Positioning mode can only be set for "modern" windows (that is, windows + * created using XPLMCreateWindowEx() and compiled against the XPLM300 SDK). + * Windows created using the deprecated XPLMCreateWindow(), or windows + * compiled against a pre-XPLM300 version of the SDK will simply get the + * "free" positioning mode. + * + */ +enum { + /* The default positioning mode. Set the window geometry and its future * + * position will be determined by its window gravity, resizing limits, and * + * user interactions. */ + xplm_WindowPositionFree = 0, + + /* Keep the window centered on the monitor you specify */ + xplm_WindowCenterOnMonitor = 1, + + /* Keep the window full screen on the monitor you specify */ + xplm_WindowFullScreenOnMonitor = 2, + + /* Like gui_window_full_screen_on_monitor, but stretches over *all* monitors * + * and popout windows. This is an obscure one... unless you have a very good * + * reason to need it, you probably don't! */ + xplm_WindowFullScreenOnAllMonitors = 3, + + /* A first-class window in the operating system, completely separate from the * + * X-Plane window(s) */ + xplm_WindowPopOut = 4, + +#if defined(XPLM301) + /* A floating window visible on the VR headset */ + xplm_WindowVR = 5, + +#endif /* XPLM301 */ + +}; +typedef int XPLMWindowPositioningMode; +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowPositioningMode + * + * Sets the policy for how X-Plane will position your window. + * + * Some positioning modes apply to a particular monitor. For those modes, you + * can pass a negative monitor index to position the window on the main + * X-Plane monitor (the screen with the X-Plane menu bar at the top). Or, if + * you have a specific monitor you want to position your window on, you can + * pass a real monitor index as received from, e.g., + * XPLMGetAllMonitorBoundsOS(). + * + * Only applies to modern windows. (Windows created using the deprecated + * XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + * the SDK will always use xplm_WindowPositionFree.) + * + */ +XPLM_API void XPLMSetWindowPositioningMode( + XPLMWindowID inWindowID, + XPLMWindowPositioningMode inPositioningMode, + int inMonitorIndex); +#endif /* XPLM300 */ + +#if defined(XPLM300) +/* + * XPLMSetWindowTitle + * + * Sets the name for a window. This only applies to windows that opted-in to + * styling as an X-Plane 11 floating window (i.e., with styling mode + * xplm_WindowDecorationRoundRectangle) when they were created using + * XPLMCreateWindowEx(). + * + */ +XPLM_API void XPLMSetWindowTitle( + XPLMWindowID inWindowID, + const char * inWindowTitle); +#endif /* XPLM300 */ + +/* + * XPLMGetWindowRefCon + * + * Returns a window's reference constant, the unique value you can use for + * your own purposes. + * + */ +XPLM_API void * XPLMGetWindowRefCon( + XPLMWindowID inWindowID); + +/* + * XPLMSetWindowRefCon + * + * Sets a window's reference constant. Use this to pass data to yourself in + * the callbacks. + * + */ +XPLM_API void XPLMSetWindowRefCon( + XPLMWindowID inWindowID, + void * inRefcon); + +/* + * XPLMTakeKeyboardFocus + * + * This routine gives a specific window keyboard focus. Keystrokes will be + * sent to that window. Pass a window ID of 0 to remove keyboard focus from + * any plugin-created windows and instead pass keyboard strokes directly to + * X-Plane. + * + */ +XPLM_API void XPLMTakeKeyboardFocus( + XPLMWindowID inWindow); + +/* + * XPLMHasKeyboardFocus + * + * Returns true (1) if the indicated window has keyboard focus. Pass a window + * ID of 0 to see if no plugin window has focus, and all keystrokes will go + * directly to X-Plane. + * + */ +XPLM_API int XPLMHasKeyboardFocus( + XPLMWindowID inWindow); + +/* + * XPLMBringWindowToFront + * + * This routine brings the window to the front of the Z-order for its layer. + * Windows are brought to the front automatically when they are created. + * Beyond that, you should make sure you are front before handling mouse + * clicks. + * + * Note that this only brings your window to the front of its layer + * (XPLMWindowLayer). Thus, if you have a window in the floating window layer + * (xplm_WindowLayerFloatingWindows), but there is a modal window (in layer + * xplm_WindowLayerModal) above you, you would still not be the true frontmost + * window after calling this. (After all, the window layers are strictly + * ordered, and no window in a lower layer can ever be above any window in a + * higher one.) + * + */ +XPLM_API void XPLMBringWindowToFront( + XPLMWindowID inWindow); + +/* + * XPLMIsWindowInFront + * + * This routine returns true if the window you passed in is the frontmost + * visible window in its layer (XPLMWindowLayer). + * + * Thus, if you have a window at the front of the floating window layer + * (xplm_WindowLayerFloatingWindows), this will return true even if there is a + * modal window (in layer xplm_WindowLayerModal) above you. (Not to worry, + * though: in such a case, X-Plane will not pass clicks or keyboard input down + * to your layer until the window above stops "eating" the input.) + * + * Note that legacy windows are always placed in layer + * xplm_WindowLayerFlightOverlay, while modern-style windows default to + * xplm_WindowLayerFloatingWindows. This means it's perfectly consistent to + * have two different plugin-created windows (one legacy, one modern) *both* + * be in the front (of their different layers!) at the same time. + * + */ +XPLM_API int XPLMIsWindowInFront( + XPLMWindowID inWindow); + +/*************************************************************************** + * KEY SNIFFERS + ***************************************************************************/ +/* + * Low-level keyboard handlers. Allows for intercepting keystrokes outside the + * normal rules of the user interface. + * + */ + + +/* + * XPLMKeySniffer_f + * + * This is the prototype for a low level key-sniffing function. Window-based + * UI _should not use this_! The windowing system provides high-level + * mediated keyboard access, via the callbacks you attach to your + * XPLMCreateWindow_t. By comparison, the key sniffer provides low level + * keyboard access. + * + * Key sniffers are provided to allow libraries to provide non-windowed user + * interaction. For example, the MUI library uses a key sniffer to do pop-up + * text entry. + * + * Return 1 to pass the key on to the next sniffer, the window manager, + * X-Plane, or whomever is down stream. Return 0 to consume the key. + * + * Warning: this API declares virtual keys as a signed character; however the + * VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + * (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + * to an unsigned char to get correct comparisons in C. + * + */ +typedef int (* XPLMKeySniffer_f)( + char inChar, + XPLMKeyFlags inFlags, + char inVirtualKey, + void * inRefcon); + +/* + * XPLMRegisterKeySniffer + * + * This routine registers a key sniffing callback. You specify whether you + * want to sniff before the window system, or only sniff keys the window + * system does not consume. You should ALMOST ALWAYS sniff non-control keys + * after the window system. When the window system consumes a key, it is + * because the user has "focused" a window. Consuming the key or taking + * action based on the key will produce very weird results. Returns + * 1 if successful. + * + */ +XPLM_API int XPLMRegisterKeySniffer( + XPLMKeySniffer_f inCallback, + int inBeforeWindows, + void * inRefcon); + +/* + * XPLMUnregisterKeySniffer + * + * This routine unregisters a key sniffer. You must unregister a key sniffer + * for every time you register one with the exact same signature. Returns 1 + * if successful. + * + */ +XPLM_API int XPLMUnregisterKeySniffer( + XPLMKeySniffer_f inCallback, + int inBeforeWindows, + void * inRefcon); + +/*************************************************************************** + * HOT KEYS + ***************************************************************************/ +/* + * Keystrokes that can be managed by others. These are lower-level than window + * keyboard handlers (i.e., callbacks you attach to your XPLMCreateWindow_t), + * but higher level than key sniffers. + * + */ + + +/* + * XPLMHotKey_f + * + * Your hot key callback simply takes a pointer of your choosing. + * + */ +typedef void (* XPLMHotKey_f)( + void * inRefcon); + +/* + * XPLMHotKeyID + * + * An opaque ID used to identify a hot key. + * + */ +typedef void * XPLMHotKeyID; + +/* + * XPLMRegisterHotKey + * + * This routine registers a hot key. You specify your preferred key stroke + * virtual key/flag combination, a description of what your callback does (so + * other plug-ins can describe the plug-in to the user for remapping) and a + * callback function and opaque pointer to pass in). A new hot key ID is + * returned. During execution, the actual key associated with your hot key + * may change, but you are insulated from this. + * + */ +XPLM_API XPLMHotKeyID XPLMRegisterHotKey( + char inVirtualKey, + XPLMKeyFlags inFlags, + const char * inDescription, + XPLMHotKey_f inCallback, + void * inRefcon); + +/* + * XPLMUnregisterHotKey + * + * Unregisters a hot key. You can only unregister your own hot keys. + * + */ +XPLM_API void XPLMUnregisterHotKey( + XPLMHotKeyID inHotKey); + +/* + * XPLMCountHotKeys + * + * Returns the number of current hot keys. + * + */ +XPLM_API int XPLMCountHotKeys(void); + +/* + * XPLMGetNthHotKey + * + * Returns a hot key by index, for iteration on all hot keys. + * + */ +XPLM_API XPLMHotKeyID XPLMGetNthHotKey( + int inIndex); + +/* + * XPLMGetHotKeyInfo + * + * Returns information about the hot key. Return NULL for any parameter you + * don't want info about. The description should be at least 512 chars long. + * + */ +XPLM_API void XPLMGetHotKeyInfo( + XPLMHotKeyID inHotKey, + char * outVirtualKey, /* Can be NULL */ + XPLMKeyFlags * outFlags, /* Can be NULL */ + char * outDescription, /* Can be NULL */ + XPLMPluginID * outPlugin); /* Can be NULL */ + +/* + * XPLMSetHotKeyCombination + * + * Remaps a hot key's keystrokes. You may remap another plugin's keystrokes. + * + */ +XPLM_API void XPLMSetHotKeyCombination( + XPLMHotKeyID inHotKey, + char inVirtualKey, + XPLMKeyFlags inFlags); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMGraphics.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMGraphics.h new file mode 100644 index 0000000..d7aef52 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMGraphics.h @@ -0,0 +1,437 @@ +#ifndef _XPLMGraphics_h_ +#define _XPLMGraphics_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMGraphics + ***************************************************************************/ +/* + * A few notes on coordinate systems: + * + * X-Plane uses three kinds of coordinates. Global coordinates are specified + * as latitude, longitude and elevation. This coordinate system never changes + * but is not very precise. + * + * OpenGL (or 'local') coordinates are cartesian and shift with the plane. + * They offer more precision and are used for 3-d OpenGL drawing. The X axis + * is aligned east-west with positive X meaning east. The Y axis is aligned + * straight up and down at the point 0,0,0 (but since the earth is round it is + * not truly straight up and down at other points). The Z axis is aligned + * north-south at 0, 0, 0 with positive Z pointing south (but since the earth + * is round it isn't exactly north-south as you move east or west of 0, 0, 0). + * One unit is one meter and the point 0,0,0 is on the surface of the earth at + * sea level for some latitude and longitude picked by the sim such that the + * user's aircraft is reasonably nearby. + * + * 2-d Panel coordinates are 2d, with the X axis horizontal and the Y axis + * vertical. The point 0,0 is the bottom left and 1024,768 is the upper + * right of the screen. This is true no matter what resolution the user's + * monitor is in; when running in higher resolution, graphics will be + * scaled. + * + * Use X-Plane's routines to convert between global and local coordinates. Do + * not attempt to do this conversion yourself; the precise 'roundness' of + * X-Plane's physics model may not match your own, and (to make things + * weirder) the user can potentially customize the physics of the current + * planet. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * X-PLANE GRAPHICS + ***************************************************************************/ +/* + * These routines allow you to use OpenGL with X-Plane. + * + */ + + +/* + * XPLMTextureID + * + * XPLM Texture IDs name well-known textures in the sim for you to use. This + * allows you to recycle textures from X-Plane, saving VRAM. + * + * *Warning*: do not use these enums. The only remaining use they have is to + * access the legacy compatibility v10 UI texture; if you need this, get it + * via the Widgets library. + * + */ +enum { + /* The bitmap that contains window outlines, button outlines, fonts, etc. */ + xplm_Tex_GeneralInterface = 0, + +#if defined(XPLM_DEPRECATED) + /* The exterior paint for the user's aircraft (daytime). */ + xplm_Tex_AircraftPaint = 1, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* The exterior light map for the user's aircraft. */ + xplm_Tex_AircraftLiteMap = 2, + +#endif /* XPLM_DEPRECATED */ + +}; +typedef int XPLMTextureID; + +/* + * XPLMSetGraphicsState + * + * XPLMSetGraphicsState changes OpenGL's fixed function pipeline state. You + * are not responsible for restoring any state that is accessed via + * XPLMSetGraphicsState, but you are responsible for not accessing this state + * directly. + * + * - inEnableFog - enables or disables fog, equivalent to: glEnable(GL_FOG); + * - inNumberTexUnits - enables or disables a number of multitexturing units. + * If the number is 0, 2d texturing is disabled entirely, as in + * glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a + * number of multitexturing units are enabled sequentially, starting with + * unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB); glEnable + * (GL_TEXTURE_2D); + * - inEnableLighting - enables or disables OpenGL lighting, e.g. + * glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + * - inEnableAlphaTesting - enables or disables the alpha test per pixel, e.g. + * glEnable(GL_ALPHA_TEST); + * - inEnableAlphaBlending - enables or disables alpha blending per pixel, + * e.g. glEnable(GL_BLEND); + * - inEnableDepthTesting - enables per pixel depth testing, as in + * glEnable(GL_DEPTH_TEST); + * - inEnableDepthWriting - enables writing back of depth information to the + * depth bufffer, as in glDepthMask(GL_TRUE); + * + * The purpose of this function is to change OpenGL state while keeping + * X-Plane aware of the state changes; this keeps X-Plane from getting + * surprised by OGL state changes, and prevents X-Plane and plug-ins from + * having to set all state before all draws; XPLMSetGraphicsState internally + * skips calls to change state that is already properly enabled. + * + * X-Plane does not have a 'default' OGL state for plug-ins with respect to + * the above state vector; plug-ins should totally set OGL state using this + * API before drawing. Use XPLMSetGraphicsState instead of any of the above + * OpenGL calls. + * + * WARNING: Any routine that performs drawing (e.g. XPLMDrawString or widget + * code) may change X-Plane's state. Always set state before drawing after + * unknown code has executed. + * + * *Deprecation Warnings*: X-Plane's lighting and fog environemnt is + * significantly more complex than the fixed function pipeline can express; + * do not assume that lighting and fog state is a good approximation for 3-d + * drawing. Prefer to use XPLMInstancing to draw objects. All calls to + * XPLMSetGraphicsState should have no fog or lighting. + * + */ +XPLM_API void XPLMSetGraphicsState( + int inEnableFog, + int inNumberTexUnits, + int inEnableLighting, + int inEnableAlphaTesting, + int inEnableAlphaBlending, + int inEnableDepthTesting, + int inEnableDepthWriting); + +/* + * XPLMBindTexture2d + * + * XPLMBindTexture2d changes what texture is bound to the 2d texturing + * target. This routine caches the current 2d texture across all texturing + * units in the sim and plug-ins, preventing extraneous binding. For + * example, consider several plug-ins running in series; if they all use the + * 'general interface' bitmap to do UI, calling this function will skip the + * rebinding of the general interface texture on all but the first plug-in, + * which can provide better frame rate son some graphics cards. + * + * inTextureID is the ID of the texture object to bind; inTextureUnit is a + * zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 + * units. (This number may increase in future versions of X-Plane.) + * + * Use this routine instead of glBindTexture(GL_TEXTURE_2D, ....); + * + */ +XPLM_API void XPLMBindTexture2d( + int inTextureNum, + int inTextureUnit); + +/* + * XPLMGenerateTextureNumbers + * + * Use this routine instead of glGenTextures to generate new texture object + * IDs. This routine historically ensured that plugins don't use texure IDs + * that X-Plane is reserving for its own use. + * + */ +XPLM_API void XPLMGenerateTextureNumbers( + int * outTextureIDs, + int inCount); + +#if defined(XPLM_DEPRECATED) +/* + * XPLMGetTexture + * + * XPLMGetTexture returns the OpenGL texture ID of an X-Plane texture based on + * a generic identifying code. For example, you can get the texture for + * X-Plane's UI bitmaps. + * + */ +XPLM_API int XPLMGetTexture( + XPLMTextureID inTexture); +#endif /* XPLM_DEPRECATED */ + +/* + * XPLMWorldToLocal + * + * This routine translates coordinates from latitude, longitude, and altitude + * to local scene coordinates. Latitude and longitude are in decimal degrees, + * and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + * meters in the local OpenGL coordinate system. + * + */ +XPLM_API void XPLMWorldToLocal( + double inLatitude, + double inLongitude, + double inAltitude, + double * outX, + double * outY, + double * outZ); + +/* + * XPLMLocalToWorld + * + * This routine translates a local coordinate triplet back into latitude, + * longitude, and altitude. Latitude and longitude are in decimal degrees, + * and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + * meters in the local OpenGL coordinate system. + * + * NOTE: world coordinates are less precise than local coordinates; you should + * try to avoid round tripping from local to world and back. + * + */ +XPLM_API void XPLMLocalToWorld( + double inX, + double inY, + double inZ, + double * outLatitude, + double * outLongitude, + double * outAltitude); + +/* + * XPLMDrawTranslucentDarkBox + * + * This routine draws a translucent dark box, partially obscuring parts of the + * screen but making text easy to read. This is the same graphics primitive + * used by X-Plane to show text files and ATC info. + * + */ +XPLM_API void XPLMDrawTranslucentDarkBox( + int inLeft, + int inTop, + int inRight, + int inBottom); + +/*************************************************************************** + * X-PLANE TEXT + ***************************************************************************/ + +/* + * XPLMFontID + * + * X-Plane features some fixed-character fonts. Each font may have its own + * metrics. + * + * WARNING: Some of these fonts are no longer supported or may have changed + * geometries. For maximum copmatibility, see the comments below. + * + * Note: X-Plane 7 supports proportional-spaced fonts. Since no measuring + * routine is available yet, the SDK will normally draw using a fixed-width + * font. You can use a dataref to enable proportional font drawing on XP7 if + * you want to. + * + */ +enum { + /* Mono-spaced font for user interface. Available in all versions of the SDK.*/ + xplmFont_Basic = 0, + +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Menus = 1, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Metal = 2, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Led = 3, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_LedWide = 4, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelHUD = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelEFIS = 6, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_PanelGPS = 7, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosGA = 8, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosBC = 9, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosHM = 10, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosGANarrow = 11, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosBCNarrow = 12, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_RadiosHMNarrow = 13, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Timer = 14, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_FullRound = 15, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_SmallRound = 16, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + /* Deprecated, do not use. */ + xplmFont_Menus_Localized = 17, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM200) + /* Proportional UI font. */ + xplmFont_Proportional = 18, + +#endif /* XPLM200 */ + +}; +typedef int XPLMFontID; + +/* + * XPLMDrawString + * + * This routine draws a NULL termianted string in a given font. Pass in the + * lower left pixel that the character is to be drawn onto. Also pass the + * character and font ID. This function returns the x offset plus the width of + * all drawn characters. The color to draw in is specified as a pointer to an + * array of three floating point colors, representing RGB intensities from 0.0 + * to 1.0. + * + */ +XPLM_API void XPLMDrawString( + float * inColorRGB, + int inXOffset, + int inYOffset, + char * inChar, + int * inWordWrapWidth, /* Can be NULL */ + XPLMFontID inFontID); + +/* + * XPLMDrawNumber + * + * This routine draws a number similar to the digit editing fields in + * PlaneMaker and data output display in X-Plane. Pass in a color, a + * position, a floating point value, and formatting info. Specify how many + * integer and how many decimal digits to show and whether to show a sign, as + * well as a character set. This routine returns the xOffset plus width of the + * string drawn. + * + */ +XPLM_API void XPLMDrawNumber( + float * inColorRGB, + int inXOffset, + int inYOffset, + double inValue, + int inDigits, + int inDecimals, + int inShowSign, + XPLMFontID inFontID); + +/* + * XPLMGetFontDimensions + * + * This routine returns the width and height of a character in a given font. + * It also tells you if the font only supports numeric digits. Pass NULL if + * you don't need a given field. Note that for a proportional font the width + * will be an arbitrary, hopefully average width. + * + */ +XPLM_API void XPLMGetFontDimensions( + XPLMFontID inFontID, + int * outCharWidth, /* Can be NULL */ + int * outCharHeight, /* Can be NULL */ + int * outDigitsOnly); /* Can be NULL */ + +#if defined(XPLM200) +/* + * XPLMMeasureString + * + * This routine returns the width in pixels of a string using a given font. + * The string is passed as a pointer plus length (and does not need to be null + * terminated); this is used to allow for measuring substrings. The return + * value is floating point; it is possible that future font drawing may allow + * for fractional pixels. + * + */ +XPLM_API float XPLMMeasureString( + XPLMFontID inFontID, + const char * inChar, + int inNumChars); +#endif /* XPLM200 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMInstance.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMInstance.h new file mode 100644 index 0000000..d2a8f2c --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMInstance.h @@ -0,0 +1,136 @@ +#ifndef _XPLMInstance_h_ +#define _XPLMInstance_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMInstance + ***************************************************************************/ +/* + * This API provides instanced drawing of X-Plane objects (.obj files). In + * contrast to old drawing APIs, which required you to draw your own objects + * per-frame, the instancing API allows you to simply register an OBJ for + * drawing, then move or manipulate it later (as needed). + * + * This provides one tremendous benefit: it keeps all dataref operations for + * your object in one place. Because datarefs are main thread only, allowing + * dataref access anywhere is a serious performance bottleneck for the + * simulator---the whole simulator has to pause and wait for each dataref + * access. This performance penalty will only grow worse as X-Plane moves + * toward an ever more heavily multithreaded engine. + * + * The instancing API allows X-Plane to isolate all dataref manipulations for + * all plugin object drawing to one place, potentially providing huge + * performance gains. + * + * Here's how it works: + * + * When an instance is created, it provides a list of all datarefs you want to + * manipulate in for the OBJ in the future. This list of datarefs replaces the + * ad-hoc collections of dataref objects previously used by art assets. Then, + * per-frame, you can manipulate the instance by passing in a "block" of + * packed floats representing the current values of the datarefs for your + * instance. (Note that the ordering of this set of packed floats must exactly + * match the ordering of the datarefs when you created your instance.) + * + */ + +#include "XPLMDefs.h" +#include "XPLMScenery.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * Instance Creation and Destruction + ***************************************************************************/ +/* + * Registers and unregisters instances. + * + */ + + +/* + * XPLMInstanceRef + * + * An opaque handle to an instance. + * + */ +typedef void * XPLMInstanceRef; + +/* + * XPLMCreateInstance + * + * XPLMCreateInstance creates a new instance, managed by your plug-in, and + * returns a handle to the instance. A few important requirements: + * + * * The object passed in must be fully loaded and returned from the XPLM + * before you can create your instance; you cannot pass a null obj ref, nor + * can you change the ref later. + * + * * If you use any custom datarefs in your object, they must be registered + * before the object is loaded. This is true even if their data will be + * provided via the instance dataref list. + * + * * The instance dataref array must be a valid ptr to an array of at least + * one item that is null terminated. That is, if you do not want any + * datarefs, you must passa ptr to an array with a null item. You cannot + * pass null for this. + * + */ +XPLM_API XPLMInstanceRef XPLMCreateInstance( + XPLMObjectRef obj, + const char ** datarefs); + +/* + * XPLMDestroyInstance + * + * XPLMDestroyInstance destroys and deallocates your instance; once called, + * you are still responsible for releasing the OBJ ref. + * + * Tip: you can release your OBJ ref after you call XPLMCreateInstance as long + * as you never use it again; the instance will maintain its own reference to + * the OBJ and the object OBJ be deallocated when the instance is destroyed. + * + */ +XPLM_API void XPLMDestroyInstance( + XPLMInstanceRef instance); + +/*************************************************************************** + * Instance Manipulation + ***************************************************************************/ + +/* + * XPLMInstanceSetPosition + * + * Updates both the position of the instance and all datarefs you registered + * for it. Call this from a flight loop callback or UI callback. + * + * __DO NOT__ call XPLMInstanceSetPosition from a drawing callback; the whole + * point of instancing is that you do not need any drawing callbacks. Setting + * instance data from a drawing callback may have undefined consequences, and + * the drawing callback hurts FPS unnecessarily. + * + * The memory pointed to by the data pointer must be large enough to hold one + * float for every data ref you have registered, and must contain valid + * floating point data. + * + * BUG: before X-Plane 11.50, if you have no dataref registered, you must + * still pass a valid pointer for data and not null. + * + */ +XPLM_API void XPLMInstanceSetPosition( + XPLMInstanceRef instance, + const XPLMDrawInfo_t * new_position, + const float * data); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMMap.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMMap.h new file mode 100644 index 0000000..8297471 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMMap.h @@ -0,0 +1,628 @@ +#ifndef _XPLMMap_h_ +#define _XPLMMap_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMMap + ***************************************************************************/ +/* + * This API allows you to create new layers within X-Plane maps. Your layers + * can draw arbitrary OpenGL, but they conveniently also have access to + * X-Plane's built-in icon and label drawing functions. + * + * As of X-Plane 11, map drawing happens in three stages: + * + * 1. backgrounds and "fill," + * 2. icons, and + * 3. labels. + * + * Thus, all background drawing gets layered beneath all icons, which likewise + * get layered beneath all labels. Within each stage, the map obeys a + * consistent layer ordering, such that "fill" layers (layers that cover a + * large amount of map area, like the terrain and clouds) appear beneath + * "markings" layers (like airport icons). This ensures that layers with fine + * details don't get obscured by layers with larger details. + * + * The XPLM map API reflects both aspects of this draw layering: you can + * register a layer as providing either markings or fill, and X-Plane will + * draw your fill layers beneath your markings layers (regardless of + * registration order). Likewise, you are guaranteed that your layer's icons + * (added from within an icon callback) will go above your layer's OpenGL + * drawing, and your labels will go above your icons. + * + * The XPLM guarantees that all plugin-created fill layers go on top of all + * native X-Plane fill layers, and all plugin-created markings layers go on + * top of all X-Plane markings layers (with the exception of the aircraft + * icons). It also guarantees that the draw order of your own plugin's layers + * will be consistent. But, for layers created by different plugins, the only + * guarantee is that we will draw all of one plugin's layers of each type + * (fill, then markings), then all of the others'; we don't guarantee which + * plugin's fill and markings layers go on top of the other's. + * + * As of X-Plane 11, maps use true cartographic projections for their drawing, + * and different maps may use different projections. For that reason, all + * drawing calls include an opaque handle for the projection you should use to + * do the drawing. Any time you would draw at a particular latitude/longitude, + * you'll need to ask the projection to translate that position into "map + * coordinates." (Note that the projection is guaranteed not to change between + * calls to your prepare-cache hook, so if you cache your map coordinates + * ahead of time, there's no need to re-project them when you actually draw.) + * + * In addition to mapping normal latitude/longitude locations into map + * coordinates, the projection APIs also let you know the current heading for + * north. (Since X-Plane 11 maps can rotate to match the heading of the user's + * aircraft, it's not safe to assume that north is at zero degrees rotation.) + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XPLM300) +/*************************************************************************** + * DRAWING CALLBACKS + ***************************************************************************/ +/* + * When you create a new map layer (using XPLMCreateMapLayer), you can provide + * any or all of these callbacks. They allow you to insert your own OpenGL + * drawing, text labels, and icons into the X-Plane map at the appropriate + * places, allowing your layer to behave as similarly to X-Plane's built-in + * layers as possible. + * + */ + + +/* + * XPLMMapLayerID + * + * This is an opaque handle for a plugin-created map layer. Pass it to the map + * drawing APIs from an appropriate callback to draw in the layer you created. + * + */ +typedef void * XPLMMapLayerID; + +/* + * XPLMMapProjectionID + * + * This is an opaque handle for a map projection. Pass it to the projection + * APIs to translate between map coordinates and latitude/longitudes. + * + */ +typedef void * XPLMMapProjectionID; + +/* + * XPLMMapStyle + * + * Indicates the visual style being drawn by the map. In X-Plane, the user can + * choose between a number of map types, and different map types may have use + * a different visual representation for the same elements (for instance, the + * visual style of the terrain layer changes drastically between the VFR and + * IFR layers), or certain layers may be disabled entirely in some map types + * (e.g., localizers are only visible in the IFR low-enroute style). + * + */ +enum { + xplm_MapStyle_VFR_Sectional = 0, + + xplm_MapStyle_IFR_LowEnroute = 1, + + xplm_MapStyle_IFR_HighEnroute = 2, + + +}; +typedef int XPLMMapStyle; + +/* + * XPLMMapDrawingCallback_f + * + * This is the OpenGL map drawing callback for plugin-created map layers. You + * can perform arbitrary OpenGL drawing from this callback, with one + * exception: changes to the Z-buffer are not permitted, and will result in + * map drawing errors. + * + * All drawing done from within this callback appears beneath all built-in + * X-Plane icons and labels, but above the built-in "fill" layers (layers + * providing major details, like terrain and water). Note, however, that the + * relative ordering between the drawing callbacks of different plugins is not + * guaranteed. + * + */ +typedef void (* XPLMMapDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapIconDrawingCallback_f + * + * This is the icon drawing callback that enables plugin-created map layers to + * draw icons using X-Plane's built-in icon drawing functionality. You can + * request an arbitrary number of PNG icons to be drawn via + * XPLMDrawMapIconFromSheet() from within this callback, but you may not + * perform any OpenGL drawing here. + * + * Icons enqueued by this function will appear above all OpenGL drawing + * (performed by your optional XPLMMapDrawingCallback_f), and above all + * built-in X-Plane map icons of the same layer type ("fill" or "markings," as + * determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + * however, that the relative ordering between the drawing callbacks of + * different plugins is not guaranteed. + * + */ +typedef void (* XPLMMapIconDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapLabelDrawingCallback_f + * + * This is the label drawing callback that enables plugin-created map layers + * to draw text labels using X-Plane's built-in labeling functionality. You + * can request an arbitrary number of text labels to be drawn via + * XPLMDrawMapLabel() from within this callback, but you may not perform any + * OpenGL drawing here. + * + * Labels enqueued by this function will appear above all OpenGL drawing + * (performed by your optional XPLMMapDrawingCallback_f), and above all + * built-in map icons and labels of the same layer type ("fill" or "markings," + * as determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + * however, that the relative ordering between the drawing callbacks of + * different plugins is not guaranteed. + * + */ +typedef void (* XPLMMapLabelDrawingCallback_f)( + XPLMMapLayerID inLayer, + const float * inMapBoundsLeftTopRightBottom, + float zoomRatio, + float mapUnitsPerUserInterfaceUnit, + XPLMMapStyle mapStyle, + XPLMMapProjectionID projection, + void * inRefcon); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * LAYER MANAGEMENT CALLBACKS + ***************************************************************************/ +/* + * These are various "bookkeeping" callbacks that your map layer can receive + * (if you provide the callback in your XPLMCreateMapLayer_t). They allow you + * to manage the lifecycle of your layer, as well as cache any + * computationally-intensive preparation you might need for drawing. + * + */ + + +/* + * XPLMMapPrepareCacheCallback_f + * + * A callback used to allow you to cache whatever information your layer needs + * to draw in the current map area. + * + * This is called each time the map's total bounds change. This is typically + * triggered by new DSFs being loaded, such that X-Plane discards old, + * now-distant DSFs and pulls in new ones. At that point, the available bounds + * of the map also change to match the new DSF area. + * + * By caching just the information you need to draw in this area, your future + * draw calls can be made faster, since you'll be able to simply "splat" your + * precomputed information each frame. + * + * We guarantee that the map projection will not change between successive + * prepare cache calls, nor will any draw call give you bounds outside these + * total map bounds. So, if you cache the projected map coordinates of all the + * items you might want to draw in the total map area, you can be guaranteed + * that no draw call will be asked to do any new work. + * + */ +typedef void (* XPLMMapPrepareCacheCallback_f)( + XPLMMapLayerID inLayer, + const float * inTotalMapBoundsLeftTopRightBottom, + XPLMMapProjectionID projection, + void * inRefcon); + +/* + * XPLMMapWillBeDeletedCallback_f + * + * Called just before your map layer gets deleted. Because SDK-created map + * layers have the same lifetime as the X-Plane map that contains them, if the + * map gets unloaded from memory, your layer will too. + * + */ +typedef void (* XPLMMapWillBeDeletedCallback_f)( + XPLMMapLayerID inLayer, + void * inRefcon); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP LAYER CREATION AND DESTRUCTION + ***************************************************************************/ +/* + * Enables the creation of new map layers. Layers are created for a particular + * instance of the X-Plane map. For instance, if you want your layer to appear + * in both the normal map interface and the Instructor Operator Station (IOS), + * you would need two separate calls to XPLMCreateMapLayer(), with two + * different values for your XPLMCreateMapLayer_t::layer_name. + * + * Your layer's lifetime will be determined by the lifetime of the map it is + * created in. If the map is destroyed (on the X-Plane side), your layer will + * be too, and you'll receive a callback to your + * XPLMMapWillBeDeletedCallback_f. + * + */ + + +/* + * XPLMMapLayerType + * + * Indicates the type of map layer you are creating. Fill layers will always + * be drawn beneath markings layers. + * + */ +enum { + /* A layer that draws "fill" graphics, like weather patterns, terrain, etc. * + * Fill layers frequently cover a large portion of the visible map area. */ + xplm_MapLayer_Fill = 0, + + /* A layer that provides markings for particular map features, like NAVAIDs, * + * airports, etc. Even dense markings layers cover a small portion of the * + * total map area. */ + xplm_MapLayer_Markings = 1, + + +}; +typedef int XPLMMapLayerType; + +/* Globally unique identifier for X-Plane's Map window, used as the * + * mapToCreateLayerIn parameter in XPLMCreateMapLayer_t */ +#define XPLM_MAP_USER_INTERFACE "XPLM_MAP_USER_INTERFACE" + +/* Globally unique identifier for X-Plane's Instructor Operator Station * + * window, used as the mapToCreateLayerIn parameter in XPLMCreateMapLayer_t */ +#define XPLM_MAP_IOS "XPLM_MAP_IOS" + +/* + * XPLMCreateMapLayer_t + * + * This structure defines all of the parameters used to create a map layer + * using XPLMCreateMapLayer. The structure will be expanded in future SDK APIs + * to include more features. Always set the structSize member to the size of + * your struct in bytes! + * + * Each layer must be associated with exactly one map instance in X-Plane. + * That map, and that map alone, will call your callbacks. Likewise, when that + * map is deleted, your layer will be as well. + * + */ +typedef struct { + /* Used to inform XPLMCreateMapLayer() of the SDK version you compiled * + * against; should always be set to sizeof(XPLMCreateMapLayer_t) */ + int structSize; + /* Globally unique string identifying the map you want this layer to appear * + * in. As of XPLM300, this is limited to one of XPLM_MAP_USER_INTERFACE or * + * XPLM_MAP_IOS */ + const char * mapToCreateLayerIn; + /* The type of layer you are creating, used to determine draw order (all * + * plugin-created markings layers are drawn above all plugin-created fill * + * layers) */ + XPLMMapLayerType layerType; + /* Optional callback to inform you this layer is being deleted (due to its * + * owning map being destroyed) */ + XPLMMapWillBeDeletedCallback_f willBeDeletedCallback; + /* Optional callback you want to use to prepare your draw cache when the map * + * bounds change (set to NULL if you don't want this callback) */ + XPLMMapPrepareCacheCallback_f prepCacheCallback; + /* Optional callback you want to use for arbitrary OpenGL drawing, which goes * + * beneath all icons in the map's layering system (set to NULL if you don't * + * want this callback) */ + XPLMMapDrawingCallback_f drawCallback; + /* Optional callback you want to use for drawing icons, which go above all * + * built-in X-Plane icons (except the aircraft) in the map's layering system * + * (set to NULL if you don't want this callback) */ + XPLMMapIconDrawingCallback_f iconCallback; + /* Optional callback you want to use for drawing map labels, which go above * + * all built-in X-Plane icons and labels (except those of aircraft) in the * + * map's layering system (set to NULL if you don't want this callback) */ + XPLMMapLabelDrawingCallback_f labelCallback; + /* True if you want a checkbox to be created in the map UI to toggle this * + * layer on and off; false if the layer should simply always be enabled */ + int showUiToggle; + /* Short label to use for this layer in the user interface */ + const char * layerName; + /* A reference to arbitrary data that will be passed to your callbacks */ + void * refcon; +} XPLMCreateMapLayer_t; + +/* + * XPLMCreateMapLayer + * + * This routine creates a new map layer. You pass in an XPLMCreateMapLayer_t + * structure with all of the fields set in. You must set the structSize of + * the structure to the size of the actual structure you used. + * + * Returns NULL if the layer creation failed. This happens most frequently + * because the map you specified in your + * XPLMCreateMapLayer_t::mapToCreateLayerIn field doesn't exist (that is, if + * XPLMMapExists() returns 0 for the specified map). You can use + * XPLMRegisterMapCreationHook() to get a notification each time a new map is + * opened in X-Plane, at which time you can create layers in it. + * + */ +XPLM_API XPLMMapLayerID XPLMCreateMapLayer( + XPLMCreateMapLayer_t * inParams); + +/* + * XPLMDestroyMapLayer + * + * Destroys a map layer you created (calling your + * XPLMMapWillBeDeletedCallback_f if applicable). Returns true if a deletion + * took place. + * + */ +XPLM_API int XPLMDestroyMapLayer( + XPLMMapLayerID inLayer); + +/* + * XPLMMapCreatedCallback_f + * + * A callback to notify your plugin that a new map has been created in + * X-Plane. This is the best time to add a custom map layer using + * XPLMCreateMapLayer(). + * + * No OpenGL drawing is permitted within this callback. + * + */ +typedef void (* XPLMMapCreatedCallback_f)( + const char * mapIdentifier, + void * refcon); + +/* + * XPLMRegisterMapCreationHook + * + * Registers your callback to receive a notification each time a new map is + * constructed in X-Plane. This callback is the best time to add your custom + * map layer using XPLMCreateMapLayer(). + * + * Note that you will not be notified about any maps that already exist---you + * can use XPLMMapExists() to check for maps that were created previously. + * + */ +XPLM_API void XPLMRegisterMapCreationHook( + XPLMMapCreatedCallback_f callback, + void * refcon); + +/* + * XPLMMapExists + * + * Returns 1 if the map with the specified identifier already exists in + * X-Plane. In that case, you can safely call XPLMCreateMapLayer() specifying + * that your layer should be added to that map. + * + */ +XPLM_API int XPLMMapExists( + const char * mapIdentifier); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP DRAWING + ***************************************************************************/ +/* + * These APIs are only valid from within a map drawing callback (one of + * XPLMIconDrawingCallback_t or XPLMMapLabelDrawingCallback_f). Your drawing + * callbacks are registered when you create a new map layer as part of your + * XPLMCreateMapLayer_t. The functions here hook into X-Plane's built-in map + * drawing functionality for icons and labels, so that you get a consistent + * style with the rest of the X-Plane map. + * + * Note that the X-Plane 11 map introduces a strict ordering: layers of type + * xplm_MapLayer_Fill get drawn beneath all xplm_MapLayer_Markings layers. + * Likewise, all OpenGL drawing (performed in your layer's + * XPLMMapDrawingCallback_f) will appear beneath any icons and labels you + * draw. + * + */ + + +/* + * XPLMMapOrientation + * + * Indicates whether a map element should be match its rotation to the map + * itself, or to the user interface. For instance, the map itself may be + * rotated such that "up" matches the user's aircraft, but you may want to + * draw a text label such that it is always rotated zero degrees relative to + * the user's perspective. In that case, you would have it draw with UI + * orientation. + * + */ +enum { + /* Orient such that a 0 degree rotation matches the map's north */ + xplm_MapOrientation_Map = 0, + + /* Orient such that a 0 degree rotation is "up" relative to the user interface*/ + xplm_MapOrientation_UI = 1, + + +}; +typedef int XPLMMapOrientation; + +/* + * XPLMDrawMapIconFromSheet + * + * Enables plugin-created map layers to draw PNG icons using X-Plane's + * built-in icon drawing functionality. Only valid from within an + * XPLMIconDrawingCallback_t (but you can request an arbitrary number of icons + * to be drawn from within your callback). + * + * X-Plane will automatically manage the memory for your texture so that it + * only has to be loaded from disk once as long as you continue drawing it + * per-frame. (When you stop drawing it, the memory may purged in a "garbage + * collection" pass, require a load from disk in the future.) + * + * Instead of having X-Plane draw a full PNG, this method allows you to use UV + * coordinates to request a portion of the image to be drawn. This allows you + * to use a single texture load (of an icon sheet, for example) to draw many + * icons. Doing so is much more efficient than drawing a dozen different small + * PNGs. + * + * The UV coordinates used here treat the texture you load as being comprised + * of a number of identically sized "cells." You specify the width and height + * in cells (ds and dt, respectively), as well as the coordinates within the + * cell grid for the sub-image you'd like to draw. + * + * Note that you can use different ds and dt values in subsequent calls with + * the same texture sheet. This enables you to use icons of different sizes in + * the same sheet if you arrange them properly in the PNG. + * + * This function is only valid from within an XPLMIconDrawingCallback_t (but + * you can request an arbitrary number of icons to be drawn from within your + * callback). + * + */ +XPLM_API void XPLMDrawMapIconFromSheet( + XPLMMapLayerID layer, + const char * inPngPath, + int s, + int t, + int ds, + int dt, + float mapX, + float mapY, + XPLMMapOrientation orientation, + float rotationDegrees, + float mapWidth); + +/* + * XPLMDrawMapLabel + * + * Enables plugin-created map layers to draw text labels using X-Plane's + * built-in labeling functionality. Only valid from within an + * XPLMMapLabelDrawingCallback_f (but you can request an arbitrary number of + * text labels to be drawn from within your callback). + * + */ +XPLM_API void XPLMDrawMapLabel( + XPLMMapLayerID layer, + const char * inText, + float mapX, + float mapY, + XPLMMapOrientation orientation, + float rotationDegrees); + +#endif /* XPLM300 */ +#if defined(XPLM300) +/*************************************************************************** + * MAP PROJECTIONS + ***************************************************************************/ +/* + * As of X-Plane 11, the map draws using true cartographic projections, and + * different maps may use different projections. Thus, to draw at a particular + * latitude and longitude, you must first transform your real-world + * coordinates into map coordinates. + * + * The map projection is also responsible for giving you the current scale of + * the map. That is, the projection can tell you how many map units correspond + * to 1 meter at a given point. + * + * Finally, the map projection can give you the current rotation of the map. + * Since X-Plane 11 maps can rotate to match the heading of the aircraft, the + * map's rotation can potentially change every frame. + * + */ + + +/* + * XPLMMapProject + * + * Projects a latitude/longitude into map coordinates. This is the inverse of + * XPLMMapUnproject(). + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API void XPLMMapProject( + XPLMMapProjectionID projection, + double latitude, + double longitude, + float * outX, + float * outY); + +/* + * XPLMMapUnproject + * + * Transforms map coordinates back into a latitude and longitude. This is the + * inverse of XPLMMapProject(). + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API void XPLMMapUnproject( + XPLMMapProjectionID projection, + float mapX, + float mapY, + double * outLatitude, + double * outLongitude); + +/* + * XPLMMapScaleMeter + * + * Returns the number of map units that correspond to a distance of one meter + * at a given set of map coordinates. + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API float XPLMMapScaleMeter( + XPLMMapProjectionID projection, + float mapX, + float mapY); + +/* + * XPLMMapGetNorthHeading + * + * Returns the heading (in degrees clockwise) from the positive Y axis in the + * cartesian mapping coordinate system to true north at the point passed in. + * You can use it as a clockwise rotational offset to align icons and other + * 2-d drawing with true north on the map, compensating for rotations in the + * map due to projection. + * + * Only valid from within a map layer callback (one of + * XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + * XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + * + */ +XPLM_API float XPLMMapGetNorthHeading( + XPLMMapProjectionID projection, + float mapX, + float mapY); + +#endif /* XPLM300 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMMenus.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMMenus.h new file mode 100644 index 0000000..f5802ab --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMMenus.h @@ -0,0 +1,290 @@ +#ifndef _XPLMMenus_h_ +#define _XPLMMenus_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMMenus + ***************************************************************************/ +/* + * Plug-ins can create menus in the menu bar of X-Plane. This is done by + * creating a menu and then creating items. Menus are referred to by an + * opaque ID. Items are referred to by (zero-based) index number. + * + * Menus are "sandboxed" between plugins---no plugin can access the menus of + * any other plugin. Furthermore, all menu indices are relative to your + * plugin's menus only; if your plugin creates two sub-menus in the Plugins + * menu at different times, it doesn't matter how many other plugins also + * create sub-menus of Plugins in the intervening time: your sub-menus will be + * given menu indices 0 and 1. (The SDK does some work in the back-end to + * filter out menus that are irrelevant to your plugin in order to deliver + * this consistency for each plugin.) + * + * When you create a menu item, you specify how we should handle clicks on + * that menu item. You can either have the XPLM trigger a callback (the + * XPLMMenuHandler_f associated with the menu that contains the item), or you + * can simply have a command be triggered (with no associated call to your + * menu handler). The advantage of the latter method is that X-Plane will + * display any keyboard shortcuts associated with the command. (In contrast, + * there are no keyboard shortcuts associated with menu handler callbacks with + * specific parameters.) + * + * Menu text in X-Plane is UTF8; X-Plane's character set covers latin, greek + * and cyrillic characters, Katakana, as well as some Japanese symbols. Some + * APIs have a inDeprecatedAndIgnored parameter that used to select a + * character set; since X-Plane 9 all localization is done via UTF-8 only. + * + */ + +#include "XPLMDefs.h" +#include "XPLMUtilities.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * XPLM MENUS + ***************************************************************************/ + +/* + * XPLMMenuCheck + * + * These enumerations define the various 'check' states for an X-Plane menu. + * 'checking' in X-Plane actually appears as a light which may or may not be + * lit. So there are three possible states. + * + */ +enum { + /* there is no symbol to the left of the menu item. */ + xplm_Menu_NoCheck = 0, + + /* the menu has a mark next to it that is unmarked (not lit). */ + xplm_Menu_Unchecked = 1, + + /* the menu has a mark next to it that is checked (lit). */ + xplm_Menu_Checked = 2, + + +}; +typedef int XPLMMenuCheck; + +/* + * XPLMMenuID + * + * This is a unique ID for each menu you create. + * + */ +typedef void * XPLMMenuID; + +/* + * XPLMMenuHandler_f + * + * A menu handler function takes two reference pointers, one for the menu + * (specified when the menu was created) and one for the item (specified when + * the item was created). + * + */ +typedef void (* XPLMMenuHandler_f)( + void * inMenuRef, + void * inItemRef); + +/* + * XPLMFindPluginsMenu + * + * This function returns the ID of the plug-ins menu, which is created for you + * at startup. + * + */ +XPLM_API XPLMMenuID XPLMFindPluginsMenu(void); + +#if defined(XPLM300) +/* + * XPLMFindAircraftMenu + * + * This function returns the ID of the menu for the currently-loaded aircraft, + * used for showing aircraft-specific commands. + * + * The aircraft menu is created by X-Plane at startup, but it remains hidden + * until it is populated via XPLMAppendMenuItem() or + * XPLMAppendMenuItemWithCommand(). + * + * Only plugins loaded with the user's current aircraft are allowed to access + * the aircraft menu. For all other plugins, this will return NULL, and any + * attempts to add menu items to it will fail. + * + */ +XPLM_API XPLMMenuID XPLMFindAircraftMenu(void); +#endif /* XPLM300 */ + +/* + * XPLMCreateMenu + * + * This function creates a new menu and returns its ID. It returns NULL if + * the menu cannot be created. Pass in a parent menu ID and an item index to + * create a submenu, or NULL for the parent menu to put the menu in the menu + * bar. The menu's name is only used if the menu is in the menubar. You also + * pass a handler function and a menu reference value. Pass NULL for the + * handler if you do not need callbacks from the menu (for example, if it only + * contains submenus). + * + * Important: you must pass a valid, non-empty menu title even if the menu is + * a submenu where the title is not visible. + * + */ +XPLM_API XPLMMenuID XPLMCreateMenu( + const char * inName, + XPLMMenuID inParentMenu, + int inParentItem, + XPLMMenuHandler_f inHandler, + void * inMenuRef); + +/* + * XPLMDestroyMenu + * + * This function destroys a menu that you have created. Use this to remove a + * submenu if necessary. (Normally this function will not be necessary.) + * + */ +XPLM_API void XPLMDestroyMenu( + XPLMMenuID inMenuID); + +/* + * XPLMClearAllMenuItems + * + * This function removes all menu items from a menu, allowing you to rebuild + * it. Use this function if you need to change the number of items on a menu. + * + */ +XPLM_API void XPLMClearAllMenuItems( + XPLMMenuID inMenuID); + +/* + * XPLMAppendMenuItem + * + * This routine appends a new menu item to the bottom of a menu and returns + * its index. Pass in the menu to add the item to, the items name, and a void + * * ref for this item. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + * Note that all menu indices returned are relative to your plugin's menus + * only; if your plugin creates two sub-menus in the Plugins menu at different + * times, it doesn't matter how many other plugins also create sub-menus of + * Plugins in the intervening time: your sub-menus will be given menu indices + * 0 and 1. (The SDK does some work in the back-end to filter out menus that + * are irrelevant to your plugin in order to deliver this consistency for each + * plugin.) + * + */ +XPLM_API int XPLMAppendMenuItem( + XPLMMenuID inMenu, + const char * inItemName, + void * inItemRef, + int inDeprecatedAndIgnored); + +#if defined(XPLM300) +/* + * XPLMAppendMenuItemWithCommand + * + * Like XPLMAppendMenuItem(), but instead of the new menu item triggering the + * XPLMMenuHandler_f of the containiner menu, it will simply execute the + * command you pass in. Using a command for your menu item allows the user to + * bind a keyboard shortcut to the command and see that shortcut represented + * in the menu. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + * Like XPLMAppendMenuItem(), all menu indices are relative to your plugin's + * menus only. + * + */ +XPLM_API int XPLMAppendMenuItemWithCommand( + XPLMMenuID inMenu, + const char * inItemName, + XPLMCommandRef inCommandToExecute); +#endif /* XPLM300 */ + +/* + * XPLMAppendMenuSeparator + * + * This routine adds a separator to the end of a menu. + * + * Returns a negative index if the append failed (due to an invalid parent + * menu argument). + * + */ +XPLM_API void XPLMAppendMenuSeparator( + XPLMMenuID inMenu); + +/* + * XPLMSetMenuItemName + * + * This routine changes the name of an existing menu item. Pass in the menu + * ID and the index of the menu item. + * + */ +XPLM_API void XPLMSetMenuItemName( + XPLMMenuID inMenu, + int inIndex, + const char * inItemName, + int inDeprecatedAndIgnored); + +/* + * XPLMCheckMenuItem + * + * Set whether a menu item is checked. Pass in the menu ID and item index. + * + */ +XPLM_API void XPLMCheckMenuItem( + XPLMMenuID inMenu, + int index, + XPLMMenuCheck inCheck); + +/* + * XPLMCheckMenuItemState + * + * This routine returns whether a menu item is checked or not. A menu item's + * check mark may be on or off, or a menu may not have an icon at all. + * + */ +XPLM_API void XPLMCheckMenuItemState( + XPLMMenuID inMenu, + int index, + XPLMMenuCheck * outCheck); + +/* + * XPLMEnableMenuItem + * + * Sets whether this menu item is enabled. Items start out enabled. + * + */ +XPLM_API void XPLMEnableMenuItem( + XPLMMenuID inMenu, + int index, + int enabled); + +#if defined(XPLM210) +/* + * XPLMRemoveMenuItem + * + * Removes one item from a menu. Note that all menu items below are moved up + * one; your plugin must track the change in index numbers. + * + */ +XPLM_API void XPLMRemoveMenuItem( + XPLMMenuID inMenu, + int inIndex); +#endif /* XPLM210 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMNavigation.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMNavigation.h new file mode 100644 index 0000000..716caf0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMNavigation.h @@ -0,0 +1,362 @@ +#ifndef _XPLMNavigation_h_ +#define _XPLMNavigation_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMNavigation + ***************************************************************************/ +/* + * The XPLM Navigation APIs give you some access to the navigation databases + * inside X-Plane. X-Plane stores all navigation information in RAM, so by + * using these APIs you can gain access to most information without having to + * go to disk or parse the files yourself. + * + * You can also use this API to program the FMS. You must use the navigation + * APIs to find the nav-aids you want to program into the FMS, since the FMS + * is powered internally by X-Plane's navigation database. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * NAVIGATION DATABASE ACCESS + ***************************************************************************/ + +/* + * XPLMNavType + * + * These enumerations define the different types of navaids. They are each + * defined with a separate bit so that they may be bit-wise added together to + * form sets of nav-aid types. + * + * NOTE: xplm_Nav_LatLon is a specific lat-lon coordinate entered into the + * FMS. It will not exist in the database, and cannot be programmed into the + * FMS. Querying the FMS for navaids will return it. Use + * XPLMSetFMSEntryLatLon to set a lat/lon waypoint. + * + */ +enum { + xplm_Nav_Unknown = 0, + + xplm_Nav_Airport = 1, + + xplm_Nav_NDB = 2, + + xplm_Nav_VOR = 4, + + xplm_Nav_ILS = 8, + + xplm_Nav_Localizer = 16, + + xplm_Nav_GlideSlope = 32, + + xplm_Nav_OuterMarker = 64, + + xplm_Nav_MiddleMarker = 128, + + xplm_Nav_InnerMarker = 256, + + xplm_Nav_Fix = 512, + + xplm_Nav_DME = 1024, + + xplm_Nav_LatLon = 2048, + + +}; +typedef int XPLMNavType; + +/* + * XPLMNavRef + * + * XPLMNavRef is an iterator into the navigation database. The navigation + * database is essentially an array, but it is not necessarily densely + * populated. The only assumption you can safely make is that like-typed + * nav-aids are grouped together. + * + * Use XPLMNavRef to refer to a nav-aid. + * + * XPLM_NAV_NOT_FOUND is returned by functions that return an XPLMNavRef when + * the iterator must be invalid. + * + */ +typedef int XPLMNavRef; + +#define XPLM_NAV_NOT_FOUND -1 + +/* + * XPLMGetFirstNavAid + * + * This returns the very first navaid in the database. Use this to traverse + * the entire database. Returns XPLM_NAV_NOT_FOUND if the nav database is + * empty. + * + */ +XPLM_API XPLMNavRef XPLMGetFirstNavAid(void); + +/* + * XPLMGetNextNavAid + * + * Given a valid nav aid ref, this routine returns the next navaid. It + * returns XPLM_NAV_NOT_FOUND if the nav aid passed in was invalid or if the + * navaid passed in was the last one in the database. Use this routine to + * iterate across all like-typed navaids or the entire database. + * + */ +XPLM_API XPLMNavRef XPLMGetNextNavAid( + XPLMNavRef inNavAidRef); + +/* + * XPLMFindFirstNavAidOfType + * + * This routine returns the ref of the first navaid of the given type in the + * database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + * database. You must pass exactly one nav aid type to this routine. + * + */ +XPLM_API XPLMNavRef XPLMFindFirstNavAidOfType( + XPLMNavType inType); + +/* + * XPLMFindLastNavAidOfType + * + * This routine returns the ref of the last navaid of the given type in the + * database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + * database. You must pass exactly one nav aid type to this routine. + * + */ +XPLM_API XPLMNavRef XPLMFindLastNavAidOfType( + XPLMNavType inType); + +/* + * XPLMFindNavAid + * + * This routine provides a number of searching capabilities for the nav + * database. XPLMFindNavAid will search through every nav aid whose type is + * within inType (multiple types may be added together) and return any + * nav-aids found based on the following rules: + * + * * If inLat and inLon are not NULL, the navaid nearest to that lat/lon will + * be returned, otherwise the last navaid found will be returned. + * + * * If inFrequency is not NULL, then any navaids considered must match this + * frequency. Note that this will screen out radio beacons that do not have + * frequency data published (like inner markers) but not fixes and airports. + * + * * If inNameFragment is not NULL, only navaids that contain the fragment in + * their name will be returned. + * + * * If inIDFragment is not NULL, only navaids that contain the fragment in + * their IDs will be returned. + * + * This routine provides a simple way to do a number of useful searches: + * * Find the nearest navaid on this frequency. + * * Find the nearest airport. + * * Find the VOR whose ID is "KBOS". + * * Find the nearest airport whose name contains "Chicago". + * + */ +XPLM_API XPLMNavRef XPLMFindNavAid( + const char * inNameFragment, /* Can be NULL */ + const char * inIDFragment, /* Can be NULL */ + float * inLat, /* Can be NULL */ + float * inLon, /* Can be NULL */ + int * inFrequency, /* Can be NULL */ + XPLMNavType inType); + +/* + * XPLMGetNavAidInfo + * + * This routine returns information about a navaid. Any non-null field is + * filled out with information if it is available. + * + * Frequencies are in the nav.dat convention as described in the X-Plane nav + * database FAQ: NDB frequencies are exact, all others are multiplied by 100. + * + * The buffer for IDs should be at least 6 chars and the buffer for names + * should be at least 41 chars, but since these values are likely to go up, I + * recommend passing at least 32 chars for IDs and 256 chars for names when + * possible. + * + * The outReg parameter tells if the navaid is within the local "region" of + * loaded DSFs. (This information may not be particularly useful to plugins.) + * The parameter is a single byte value 1 for true or 0 for false, not a C + * string. + * + */ +XPLM_API void XPLMGetNavAidInfo( + XPLMNavRef inRef, + XPLMNavType * outType, /* Can be NULL */ + float * outLatitude, /* Can be NULL */ + float * outLongitude, /* Can be NULL */ + float * outHeight, /* Can be NULL */ + int * outFrequency, /* Can be NULL */ + float * outHeading, /* Can be NULL */ + char * outID, /* Can be NULL */ + char * outName, /* Can be NULL */ + char * outReg); /* Can be NULL */ + +/*************************************************************************** + * FLIGHT MANAGEMENT COMPUTER + ***************************************************************************/ +/* + * Note: the FMS works based on an array of entries. Indices into the array + * are zero-based. Each entry is a nav-aid plus an altitude. The FMS tracks + * the currently displayed entry and the entry that it is flying to. + * + * The FMS must be programmed with contiguous entries, so clearing an entry at + * the end shortens the effective flight plan. There is a max of 100 + * waypoints in the flight plan. + * + */ + + +/* + * XPLMCountFMSEntries + * + * This routine returns the number of entries in the FMS. + * + */ +XPLM_API int XPLMCountFMSEntries(void); + +/* + * XPLMGetDisplayedFMSEntry + * + * This routine returns the index of the entry the pilot is viewing. + * + */ +XPLM_API int XPLMGetDisplayedFMSEntry(void); + +/* + * XPLMGetDestinationFMSEntry + * + * This routine returns the index of the entry the FMS is flying to. + * + */ +XPLM_API int XPLMGetDestinationFMSEntry(void); + +/* + * XPLMSetDisplayedFMSEntry + * + * This routine changes which entry the FMS is showing to the index specified. + * + */ +XPLM_API void XPLMSetDisplayedFMSEntry( + int inIndex); + +/* + * XPLMSetDestinationFMSEntry + * + * This routine changes which entry the FMS is flying the aircraft toward. + * + */ +XPLM_API void XPLMSetDestinationFMSEntry( + int inIndex); + +/* + * XPLMGetFMSEntryInfo + * + * This routine returns information about a given FMS entry. If the entry is + * an airport or navaid, a reference to a nav entry can be returned allowing + * you to find additional information (such as a frequency, ILS heading, name, + * etc.). Note that this reference can be XPLM_NAV_NOT_FOUND until the + * information has been looked up asynchronously, so after flightplan changes, + * it might take up to a second for this field to become populated. The other + * information is available immediately. For a lat/lon entry, the lat/lon is + * returned by this routine but the navaid cannot be looked up (and the + * reference will be XPLM_NAV_NOT_FOUND). FMS name entry buffers should be at + * least 256 chars in length. + * + * WARNING: Due to a bug in X-Plane prior to 11.31, the navaid reference will + * not be set to XPLM_NAV_NOT_FOUND while no data is available, and instead + * just remain the value of the variable that you passed the pointer to. + * Therefore, always initialize the variable to XPLM_NAV_NOT_FOUND before + * passing the pointer to this function. + * + */ +XPLM_API void XPLMGetFMSEntryInfo( + int inIndex, + XPLMNavType * outType, /* Can be NULL */ + char * outID, /* Can be NULL */ + XPLMNavRef * outRef, /* Can be NULL */ + int * outAltitude, /* Can be NULL */ + float * outLat, /* Can be NULL */ + float * outLon); /* Can be NULL */ + +/* + * XPLMSetFMSEntryInfo + * + * This routine changes an entry in the FMS to have the destination navaid + * passed in and the altitude specified. Use this only for airports, fixes, + * and radio-beacon navaids. Currently of radio beacons, the FMS can only + * support VORs and NDBs. Use the routines below to clear or fly to a lat/lon. + * + */ +XPLM_API void XPLMSetFMSEntryInfo( + int inIndex, + XPLMNavRef inRef, + int inAltitude); + +/* + * XPLMSetFMSEntryLatLon + * + * This routine changes the entry in the FMS to a lat/lon entry with the given + * coordinates. + * + */ +XPLM_API void XPLMSetFMSEntryLatLon( + int inIndex, + float inLat, + float inLon, + int inAltitude); + +/* + * XPLMClearFMSEntry + * + * This routine clears the given entry, potentially shortening the flight + * plan. + * + */ +XPLM_API void XPLMClearFMSEntry( + int inIndex); + +/*************************************************************************** + * GPS RECEIVER + ***************************************************************************/ +/* + * These APIs let you read data from the GPS unit. + * + */ + +/* + * XPLMGetGPSDestinationType + * + * This routine returns the type of the currently selected GPS destination, + * one of fix, airport, VOR or NDB. + * + */ +XPLM_API XPLMNavType XPLMGetGPSDestinationType(void); + +/* + * XPLMGetGPSDestination + * + * This routine returns the current GPS destination. + * + */ +XPLM_API XPLMNavRef XPLMGetGPSDestination(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMPlanes.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMPlanes.h new file mode 100644 index 0000000..486302d --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMPlanes.h @@ -0,0 +1,287 @@ +#ifndef _XPLMPlanes_h_ +#define _XPLMPlanes_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMPlanes + ***************************************************************************/ +/* + * The XPLMPlanes APIs allow you to control the various aircraft in X-Plane, + * both the user's and the sim's. + * + * *Note*: unlike almost all other APIs in the SDK, aircraft paths are _full_ + * file system paths for historical reasons. You'll need to prefix all + * relative paths with the X-Plane path as accessed via XPLMGetSystemPath. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * USER AIRCRAFT ACCESS + ***************************************************************************/ + +/* + * XPLMSetUsersAircraft + * + * This routine changes the user's aircraft. Note that this will reinitialize + * the user to be on the nearest airport's first runway. Pass in a full path + * (hard drive and everything including the .acf extension) to the .acf file. + * + */ +XPLM_API void XPLMSetUsersAircraft( + const char * inAircraftPath); +/* + * XPLMPlaceUserAtAirport + * + * This routine places the user at a given airport. Specify the airport by + * its X-Plane airport ID (e.g. 'KBOS'). + * + */ +XPLM_API void XPLMPlaceUserAtAirport( + const char * inAirportCode); +#if defined(XPLM300) +/* + * XPLMPlaceUserAtLocation + * + * Places the user at a specific location after performing any necessary + * scenery loads. + * + * As with in-air starts initiated from the X-Plane user interface, the + * aircraft will always start with its engines running, regardless of the + * user's preferences (i.e., regardless of what the dataref + * `sim/operation/prefs/startup_running` says). + * + */ +XPLM_API void XPLMPlaceUserAtLocation( + double latitudeDegrees, + double longitudeDegrees, + float elevationMetersMSL, + float headingDegreesTrue, + float speedMetersPerSecond); +#endif /* XPLM300 */ +/*************************************************************************** + * GLOBAL AIRCRAFT ACCESS + ***************************************************************************/ + +/* The user's aircraft is always index 0. */ +#define XPLM_USER_AIRCRAFT 0 +#if defined(XPLM_DEPRECATED) +/* + * XPLMPlaneDrawState_t + * + * This structure contains additional plane parameter info to be passed to + * draw plane. Make sure to fill in the size of the structure field with + * sizeof(XPLMDrawPlaneState_t) so that the XPLM can tell how many fields you + * knew about when compiling your plugin (since more fields may be added + * later). + * + * Most of these fields are ratios from 0 to 1 for control input. X-Plane + * calculates what the actual controls look like based on the .acf file for + * that airplane. Note for the yoke inputs, this is what the pilot of the + * plane has commanded (post artificial stability system if there were one) + * and affects aelerons, rudder, etc. It is not necessarily related to the + * actual position of the plane! + * + */ +typedef struct { + /* The size of the draw state struct. */ + int structSize; + /* A ratio from [0..1] describing how far the landing gear is extended. */ + float gearPosition; + /* Ratio of flap deployment, 0 = up, 1 = full deploy. */ + float flapRatio; + /* Ratio of spoiler deployment, 0 = none, 1 = full deploy. */ + float spoilerRatio; + /* Ratio of speed brake deployment, 0 = none, 1 = full deploy. */ + float speedBrakeRatio; + /* Ratio of slat deployment, 0 = none, 1 = full deploy. */ + float slatRatio; + /* Wing sweep ratio, 0 = forward, 1 = swept. */ + float wingSweep; + /* Thrust power, 0 = none, 1 = full fwd, -1 = full reverse. */ + float thrust; + /* Total pitch input for this plane. */ + float yokePitch; + /* Total Heading input for this plane. */ + float yokeHeading; + /* Total Roll input for this plane. */ + float yokeRoll; +} XPLMPlaneDrawState_t; +#endif /* XPLM_DEPRECATED */ +/* + * XPLMCountAircraft + * + * This function returns the number of aircraft X-Plane is capable of having, + * as well as the number of aircraft that are currently active. These numbers + * count the user's aircraft. It can also return the plugin that is currently + * controlling aircraft. In X-Plane 7, this routine reflects the number of + * aircraft the user has enabled in the rendering options window. + * + */ +XPLM_API void XPLMCountAircraft( + int * outTotalAircraft, + int * outActiveAircraft, + XPLMPluginID * outController); +/* + * XPLMGetNthAircraftModel + * + * This function returns the aircraft model for the Nth aircraft. Indices are + * zero based, with zero being the user's aircraft. The file name should be + * at least 256 chars in length; the path should be at least 512 chars in + * length. + * + */ +XPLM_API void XPLMGetNthAircraftModel( + int inIndex, + char * outFileName, + char * outPath); +/*************************************************************************** + * EXCLUSIVE AIRCRAFT ACCESS + ***************************************************************************/ +/* + * The following routines require exclusive access to the airplane APIs. Only + * one plugin may have this access at a time. + * + */ + + +/* + * XPLMPlanesAvailable_f + * + * Your airplanes available callback is called when another plugin gives up + * access to the multiplayer planes. Use this to wait for access to + * multiplayer. + * + */ +typedef void (* XPLMPlanesAvailable_f)( + void * inRefcon); + +/* + * XPLMAcquirePlanes + * + * XPLMAcquirePlanes grants your plugin exclusive access to the aircraft. It + * returns 1 if you gain access, 0 if you do not. + * + * inAircraft - pass in an array of pointers to strings specifying the planes + * you want loaded. For any plane index you do not want loaded, pass a + * 0-length string. Other strings should be full paths with the .acf + * extension. NULL terminates this array, or pass NULL if there are no planes + * you want loaded. + * + * If you pass in a callback and do not receive access to the planes your + * callback will be called when the airplanes are available. If you do receive + * airplane access, your callback will not be called. + * + */ +XPLM_API int XPLMAcquirePlanes( + char ** inAircraft, /* Can be NULL */ + XPLMPlanesAvailable_f inCallback, + void * inRefcon); + +/* + * XPLMReleasePlanes + * + * Call this function to release access to the planes. Note that if you are + * disabled, access to planes is released for you and you must reacquire it. + * + */ +XPLM_API void XPLMReleasePlanes(void); + +/* + * XPLMSetActiveAircraftCount + * + * This routine sets the number of active planes. If you pass in a number + * higher than the total number of planes availables, only the total number of + * planes available is actually used. + * + */ +XPLM_API void XPLMSetActiveAircraftCount( + int inCount); + +/* + * XPLMSetAircraftModel + * + * This routine loads an aircraft model. It may only be called if you have + * exclusive access to the airplane APIs. Pass in the path of the model with + * the .acf extension. The index is zero based, but you may not pass in 0 + * (use XPLMSetUsersAircraft to load the user's aircracft). + * + */ +XPLM_API void XPLMSetAircraftModel( + int inIndex, + const char * inAircraftPath); + +/* + * XPLMDisableAIForPlane + * + * This routine turns off X-Plane's AI for a given plane. The plane will + * continue to draw and be a real plane in X-Plane, but will not move itself. + * + */ +XPLM_API void XPLMDisableAIForPlane( + int inPlaneIndex); + +#if defined(XPLM_DEPRECATED) +/* + * XPLMDrawAircraft + * + * WARNING: Aircraft drawing via this API is deprecated and will not work in + * future versions of X-Plane. Use XPLMInstance for 3-d drawing of custom + * aircraft models. + * + * This routine draws an aircraft. It can only be called from a 3-d drawing + * callback. Pass in the position of the plane in OpenGL local coordinates + * and the orientation of the plane. A 1 for full drawing indicates that the + * whole plane must be drawn; a 0 indicates you only need the nav lights + * drawn. (This saves rendering time when planes are far away.) + * + */ +XPLM_API void XPLMDrawAircraft( + int inPlaneIndex, + float inX, + float inY, + float inZ, + float inPitch, + float inRoll, + float inYaw, + int inFullDraw, + XPLMPlaneDrawState_t * inDrawStateInfo); +#endif /* XPLM_DEPRECATED */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMReinitUsersPlane + * + * WARNING: DO NOT USE. Use XPLMPlaceUserAtAirport or + * XPLMPlaceUserAtLocation. + * + * This function recomputes the derived flight model data from the aircraft + * structure in memory. If you have used the data access layer to modify the + * aircraft structure, use this routine to resynchronize X-Plane; since + * X-Plane works at least partly from derived values, the sim will not behave + * properly until this is called. + * + * WARNING: this routine does not necessarily place the airplane at the + * airport; use XPLMSetUsersAircraft to be compatible. This routine is + * provided to do special experimentation with flight models without resetting + * flight. + * + */ +XPLM_API void XPLMReinitUsersPlane(void); +#endif /* XPLM_DEPRECATED */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMPlugin.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMPlugin.h new file mode 100644 index 0000000..be5d06c --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMPlugin.h @@ -0,0 +1,422 @@ +#ifndef _XPLMPlugin_h_ +#define _XPLMPlugin_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMPlugin + ***************************************************************************/ +/* + * These APIs provide facilities to find and work with other plugins and + * manage other plugins. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FINDING PLUGINS + ***************************************************************************/ +/* + * These APIs allow you to find another plugin or yourself, or iterate across + * all plugins. For example, if you wrote an FMS plugin that needed to talk + * to an autopilot plugin, you could use these APIs to locate the autopilot + * plugin. + * + */ + + +/* + * XPLMGetMyID + * + * This routine returns the plugin ID of the calling plug-in. Call this to + * get your own ID. + * + */ +XPLM_API XPLMPluginID XPLMGetMyID(void); + +/* + * XPLMCountPlugins + * + * This routine returns the total number of plug-ins that are loaded, both + * disabled and enabled. + * + */ +XPLM_API int XPLMCountPlugins(void); + +/* + * XPLMGetNthPlugin + * + * This routine returns the ID of a plug-in by index. Index is 0 based from 0 + * to XPLMCountPlugins-1, inclusive. Plugins may be returned in any arbitrary + * order. + * + */ +XPLM_API XPLMPluginID XPLMGetNthPlugin( + int inIndex); + +/* + * XPLMFindPluginByPath + * + * This routine returns the plug-in ID of the plug-in whose file exists at the + * passed in absolute file system path. XPLM_NO_PLUGIN_ID is returned if the + * path does not point to a currently loaded plug-in. + * + */ +XPLM_API XPLMPluginID XPLMFindPluginByPath( + const char * inPath); + +/* + * XPLMFindPluginBySignature + * + * This routine returns the plug-in ID of the plug-in whose signature matches + * what is passed in or XPLM_NO_PLUGIN_ID if no running plug-in has this + * signature. Signatures are the best way to identify another plug-in as they + * are independent of the file system path of a plug-in or the human-readable + * plug-in name, and should be unique for all plug-ins. Use this routine to + * locate another plugin that your plugin interoperates with + * + */ +XPLM_API XPLMPluginID XPLMFindPluginBySignature( + const char * inSignature); + +/* + * XPLMGetPluginInfo + * + * This routine returns information about a plug-in. Each parameter should be + * a pointer to a buffer of at least + * 256 characters, or NULL to not receive the information. + * + * outName - the human-readable name of the plug-in. outFilePath - the + * absolute file path to the file that contains this plug-in. outSignature - a + * unique string that identifies this plug-in. outDescription - a + * human-readable description of this plug-in. + * + */ +XPLM_API void XPLMGetPluginInfo( + XPLMPluginID inPlugin, + char * outName, /* Can be NULL */ + char * outFilePath, /* Can be NULL */ + char * outSignature, /* Can be NULL */ + char * outDescription); /* Can be NULL */ + +/*************************************************************************** + * ENABLING/DISABLING PLUG-INS + ***************************************************************************/ +/* + * These routines are used to work with plug-ins and manage them. Most + * plugins will not need to use these APIs. + * + */ + + +/* + * XPLMIsPluginEnabled + * + * Returns whether the specified plug-in is enabled for running. + * + */ +XPLM_API int XPLMIsPluginEnabled( + XPLMPluginID inPluginID); + +/* + * XPLMEnablePlugin + * + * This routine enables a plug-in if it is not already enabled. It returns 1 + * if the plugin was enabled or successfully enables itself, 0 if it does not. + * Plugins may fail to enable (for example, if resources cannot be acquired) + * by returning 0 from their XPluginEnable callback. + * + */ +XPLM_API int XPLMEnablePlugin( + XPLMPluginID inPluginID); + +/* + * XPLMDisablePlugin + * + * This routine disableds an enabled plug-in. + * + */ +XPLM_API void XPLMDisablePlugin( + XPLMPluginID inPluginID); + +/* + * XPLMReloadPlugins + * + * This routine reloads all plug-ins. Once this routine is called and you + * return from the callback you were within (e.g. a menu select callback) you + * will receive your XPluginDisable and XPluginStop callbacks and your DLL + * will be unloaded, then the start process happens as if the sim was starting + * up. + * + */ +XPLM_API void XPLMReloadPlugins(void); + +/*************************************************************************** + * INTERPLUGIN MESSAGING + ***************************************************************************/ +/* + * Plugin messages are defined as 32-bit integers. Messages below 0x00FFFFFF + * are reserved for X-Plane and the plugin SDK. + * + * Messages come with a pointer parameter; the meaning of this pointer depends + * on the message itself. In some messages, the pointer parameter contains an + * actual typed pointer to data that can be inspected in the plugin; in these + * cases the documentation will state that the parameter "points to" + * information. + * + * in other cases, the value of the pointer is actually an integral number + * stuffed into the pointer's storage. In these second cases, the pointer + * parameter needs to be cast, not dereferenced. In these caess, the + * documentation will state that the parameter "contains" a value, which will + * always be an integral type. + * + * Some messages don't use the pointer parameter - in this case your plugin + * should ignore it. + * + * Messages have two conceptual uses: notifications and commands. Commands + * are sent from one plugin to another to induce behavior; notifications are + * sent from one plugin to all others for informational purposes. It is + * important that commands and notifications not have the same values because + * this could cause a notification sent by one plugin to accidentally induce a + * command in another. + * + * By convention, plugin-defined notifications should have the high bit set + * (e.g. be greater or equal to unsigned 0x8000000) while commands should have + * this bit be cleared. + * + * The following messages are sent to your plugin by X-Plane. + * + */ + + +/* This message is sent to your plugin whenever the user's plane crashes. The * + * parameter is ignored. */ +#define XPLM_MSG_PLANE_CRASHED 101 + +/* This message is sent to your plugin whenever a new plane is loaded. The * + * parameter contains the index number of the plane being loaded; 0 indicates * + * the user's plane. */ +#define XPLM_MSG_PLANE_LOADED 102 + +/* This messages is sent whenever the user's plane is positioned at a new * + * airport. The parameter is ignored. */ +#define XPLM_MSG_AIRPORT_LOADED 103 + +/* This message is sent whenever new scenery is loaded. Use datarefs to * + * determine the new scenery files that were loaded. The parameter is ignored.*/ +#define XPLM_MSG_SCENERY_LOADED 104 + +/* This message is sent whenever the user adjusts the number of X-Plane * + * aircraft models. You must use XPLMCountPlanes to find out how many planes * + * are now available. This message will only be sent in XP7 and higher * + * because in XP6 the number of aircraft is not user-adjustable. The parameter* + * is ignored. */ +#define XPLM_MSG_AIRPLANE_COUNT_CHANGED 105 + +#if defined(XPLM200) +/* This message is sent to your plugin whenever a plane is unloaded. The * + * parameter contains the index number of the plane being unloaded; 0 * + * indicates the user's plane. The parameter is of type int, passed as the * + * value of the pointer. (That is: the parameter is an int, not a pointer to * + * an int.) */ +#define XPLM_MSG_PLANE_UNLOADED 106 +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* This message is sent to your plugin right before X-Plane writes its * + * preferences file. You can use this for two purposes: to write your own * + * preferences, and to modify any datarefs to influence preferences output. * + * For example, if your plugin temporarily modifies saved preferences, you can* + * put them back to their default values here to avoid having the tweaks be * + * persisted if your plugin is not loaded on the next invocation of X-Plane. * + * The parameter is ignored. */ +#define XPLM_MSG_WILL_WRITE_PREFS 107 +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* This message is sent to your plugin right after a livery is loaded for an * + * airplane. You can use this to check the new livery (via datarefs) and * + * react accordingly. The parameter contains the index number of the aircraft* + * whose livery is changing. */ +#define XPLM_MSG_LIVERY_LOADED 108 +#endif /* XPLM210 */ + +#if defined(XPLM301) +/* Sent to your plugin right before X-Plane enters virtual reality mode (at * + * which time any windows that are not positioned in VR mode will no longer be* + * visible to the user). The parameter is unused and should be ignored. */ +#define XPLM_MSG_ENTERED_VR 109 +#endif /* XPLM301 */ + +#if defined(XPLM301) +/* Sent to your plugin right before X-Plane leaves virtual reality mode (at * + * which time you may want to clean up windows that are positioned in VR * + * mode). The parameter is unused and should be ignored. */ +#define XPLM_MSG_EXITING_VR 110 +#endif /* XPLM301 */ + +#if defined(XPLM303) +/* Sent to your plugin if another plugin wants to take over AI planes. If you * + * are a synthetic traffic provider, that probably means a plugin for an * + * online network has connected and wants to supply aircraft flown by real * + * humans and you should cease to provide synthetic traffic. If however you * + * are providing online traffic from real humans, you probably don't want to * + * disconnect, in which case you just ignore this message. The sender is the * + * plugin ID of the plugin asking for control of the planes now. You can use * + * it to find out who is requesting and whether you should yield to them. * + * Synthetic traffic providers should always yield to online networks. The * + * parameter is unused and should be ignored. */ +#define XPLM_MSG_RELEASE_PLANES 111 +#endif /* XPLM303 */ + +/* + * XPLMSendMessageToPlugin + * + * This function sends a message to another plug-in or X-Plane. Pass + * XPLM_NO_PLUGIN_ID to broadcast to all plug-ins. Only enabled plug-ins with + * a message receive function receive the message. + * + */ +XPLM_API void XPLMSendMessageToPlugin( + XPLMPluginID inPlugin, + int inMessage, + void * inParam); + +#if defined(XPLM200) +/*************************************************************************** + * Plugin Features API + ***************************************************************************/ +/* + * The plugin features API allows your plugin to "sign up" for additional + * capabilities and plugin system features that are normally disabled for + * backward compatibility. This allows advanced plugins to "opt-in" to new + * behavior. + * + * Each feature is defined by a permanent string name. The feature string + * names will vary with the particular installation of X-Plane, so plugins + * should not expect a feature to be guaranteed present. + * + * XPLM_WANTS_REFLECTIONS + * ---------------------- + * + * Available in the SDK 2.0 and later for X-Plane 9, enabling this capability + * causes your plugin to receive drawing hook callbacks when X-Plane builds + * its off-screen reflection and shadow rendering passes. Plugins should + * enable this and examine the dataref sim/graphics/view/plane_render_type to + * determine whether the drawing callback is for a reflection, shadow + * calculation, or the main screen. Rendering can be simlified or omitted for + * reflections, and non-solid drawing should be skipped for shadow + * calculations. + * + * **Note**: direct drawing via draw callbacks is not recommended; use the + * XPLMInstance API to create object models instead. + * + * XPLM_USE_NATIVE_PATHS + * --------------------- + * + * available in the SDK 2.1 and later for X-Plane 10, this modifies the plugin + * system to use Unix-style paths on all operating systems. With this enabled: + * + * * OS X paths will match the native OS X Unix. + * * Windows will use forward slashes but preserve C:\ or another drive letter + * when using complete file paths. + * * Linux uses its native file system path scheme. + * + * Without this enabled: + * + * * OS X will use CFM file paths separated by a colon. + * * Windows will use back-slashes and conventional DOS paths. + * * Linux uses its native file system path scheme. + * + * All plugins should enable this feature on OS X to access the native file + * system. + * + * XPLM_USE_NATIVE_WIDGET_WINDOWS + * ------------------------------ + * + * Available in the SDK 3.0.2 SDK, this capability tells the widgets library + * to use new, modern X-Plane backed XPLMDisplay windows to anchor all widget + * trees. Without it, widgets will always use legacy windows. + * + * Plugins should enable this to allow their widget hierarchies to respond to + * the user's UI size settings and to map widget-based windwos to a VR HMD. + * + * Before enabling this, make sure any custom widget code in your plugin is + * prepared to cope with the UI coordinate system not being th same as the + * OpenGL window coordinate system. + * + */ + + +/* + * XPLMFeatureEnumerator_f + * + * You pass an XPLMFeatureEnumerator_f to get a list of all features supported + * by a given version running version of X-Plane. This routine is called once + * for each feature. + * + */ +typedef void (* XPLMFeatureEnumerator_f)( + const char * inFeature, + void * inRef); + +/* + * XPLMHasFeature + * + * This returns 1 if the given installation of X-Plane supports a feature, or + * 0 if it does not. + * + */ +XPLM_API int XPLMHasFeature( + const char * inFeature); + +/* + * XPLMIsFeatureEnabled + * + * This returns 1 if a feature is currently enabled for your plugin, or 0 if + * it is not enabled. It is an error to call this routine with an unsupported + * feature. + * + */ +XPLM_API int XPLMIsFeatureEnabled( + const char * inFeature); + +/* + * XPLMEnableFeature + * + * This routine enables or disables a feature for your plugin. This will + * change the running behavior of X-Plane and your plugin in some way, + * depending on the feature. + * + */ +XPLM_API void XPLMEnableFeature( + const char * inFeature, + int inEnable); + +/* + * XPLMEnumerateFeatures + * + * This routine calls your enumerator callback once for each feature that this + * running version of X-Plane supports. Use this routine to determine all of + * the features that X-Plane can support. + * + */ +XPLM_API void XPLMEnumerateFeatures( + XPLMFeatureEnumerator_f inEnumerator, + void * inRef); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMProcessing.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMProcessing.h new file mode 100644 index 0000000..94ef0c4 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMProcessing.h @@ -0,0 +1,264 @@ +#ifndef _XPLMProcessing_h_ +#define _XPLMProcessing_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMProcessing + ***************************************************************************/ +/* + * This API allows you to get regular callbacks during the flight loop, the + * part of X-Plane where the plane's position calculates the physics of + * flight, etc. Use these APIs to accomplish periodic tasks like logging data + * and performing I/O. + * + * You can receive a callback either just before or just after the per-frame + * physics calculations happen - you can use post-FM callbacks to "patch" the + * flight model after it has run. + * + * If the user has set the number of flight model iterations per frame greater + * than one your plugin will _not_ see this; these integrations run on the + * sub-section of the flight model where iterations improve responsiveness + * (e.g. physical integration, not simple systems tracking) and are thus + * opaque to plugins. + * + * Flight loop scheduling, when scheduled by time, is scheduled by a "first + * callback after the deadline" schedule, e.g. your callbacks will always be + * slightly late to ensure that we don't run faster than your deadline. + * + * WARNING: Do NOT use these callbacks to draw! You cannot draw during flight + * loop callbacks. Use the drawing callbacks (see XPLMDisplay for more info) + * for graphics. (One exception: you can use a post-flight loop callback to + * update your own off-screen FBOs.) + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FLIGHT LOOP CALLBACKS + ***************************************************************************/ + +#if defined(XPLM210) +/* + * XPLMFlightLoopPhaseType + * + * You can register a flight loop callback to run either before or after the + * flight model is integrated by X-Plane. + * + */ +enum { + /* Your callback runs before X-Plane integrates the flight model. */ + xplm_FlightLoop_Phase_BeforeFlightModel = 0, + + /* Your callback runs after X-Plane integrates the flight model. */ + xplm_FlightLoop_Phase_AfterFlightModel = 1, + + +}; +typedef int XPLMFlightLoopPhaseType; +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMFlightLoopID + * + * This is an opaque identifier for a flight loop callback. You can use this + * identifier to easily track and remove your callbacks, or to use the new + * flight loop APIs. + * + */ +typedef void * XPLMFlightLoopID; +#endif /* XPLM210 */ + +/* + * XPLMFlightLoop_f + * + * This is your flight loop callback. Each time the flight loop is iterated + * through, you receive this call at the end. + * + * Flight loop callbacks receive a number of input timing parameters. These + * input timing parameters are not particularly useful; you may need to track + * your own timing data (e.g. by reading datarefs). The input parameters are: + * + * - inElapsedSinceLastCall: the wall time since your last callback. + * - inElapsedTimeSinceLastFlightLoop: the wall time since any flight loop was + * dispatched. + * - inCounter: a monotonically increasing counter, bumped once per flight + * loop dispatch from the sim. + * - inRefcon: your own ptr constant from when you regitered yor callback. + * + * Your return value controls when you will next be called. + * + * - Return 0 to stop receiving callbacks. + * - Pass a positive number to specify how many seconds until the next + * callback. (You will be called at or after this time, not before.) + * - Pass a negative number to specify how many loops must go by until you + * are called. For example, -1.0 means call me the very next loop. + * + * Try to run your flight loop as infrequently as is practical, and suspend it + * (using return value 0) when you do not need it; lots of flight loop + * callbacks that do nothing lowers X-Plane's frame rate. + * + * Your callback will NOT be unregistered if you return 0; it will merely be + * inactive. + * + */ +typedef float (* XPLMFlightLoop_f)( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void * inRefcon); + +#if defined(XPLM210) +/* + * XPLMCreateFlightLoop_t + * + * XPLMCreateFlightLoop_t contains the parameters to create a new flight loop + * callback. The strsucture can be expanded in future SDKs - always set + * structSize to the size of your structure in bytes. + * + */ +typedef struct { + int structSize; + XPLMFlightLoopPhaseType phase; + XPLMFlightLoop_f callbackFunc; + void * refcon; +} XPLMCreateFlightLoop_t; +#endif /* XPLM210 */ + +/* + * XPLMGetElapsedTime + * + * This routine returns the elapsed time since the sim started up in decimal + * seconds. This is a wall timer; it keeps counting upward even if the sim is + * pasued. + * + * __WARNING__: XPLMGetElapsedTime is not a very good timer! It lacks + * precision in both its data type and its source. Do not attempt to use it + * for timing critical applications like network multiplayer. + * + */ +XPLM_API float XPLMGetElapsedTime(void); + +/* + * XPLMGetCycleNumber + * + * This routine returns a counter starting at zero for each sim cycle + * computed/video frame rendered. + * + */ +XPLM_API int XPLMGetCycleNumber(void); + +/* + * XPLMRegisterFlightLoopCallback + * + * This routine registers your flight loop callback. Pass in a pointer to a + * flight loop function and a refcon. inInterval defines when you will be + * called. Pass in a positive number to specify seconds from registration time + * to the next callback. Pass in a negative number to indicate when you will + * be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to not be + * called; your callback will be inactive. + * + * (This legacy function only installs pre-flight-loop callbacks; use + * XPLMCreateFlightLoop for more control.) + * + */ +XPLM_API void XPLMRegisterFlightLoopCallback( + XPLMFlightLoop_f inFlightLoop, + float inInterval, + void * inRefcon); + +/* + * XPLMUnregisterFlightLoopCallback + * + * This routine unregisters your flight loop callback. Do NOT call it from + * your flight loop callback. Once your flight loop callback is unregistered, + * it will not be called again. + * + * Only use this on flight loops registered via + * XPLMRegisterFlightLoopCallback. + * + */ +XPLM_API void XPLMUnregisterFlightLoopCallback( + XPLMFlightLoop_f inFlightLoop, + void * inRefcon); + +/* + * XPLMSetFlightLoopCallbackInterval + * + * This routine sets when a callback will be called. Do NOT call it from your + * callback; use the return value of the callback to change your callback + * interval from inside your callback. + * + * inInterval is formatted the same way as in XPLMRegisterFlightLoopCallback; + * positive for seconds, negative for cycles, and 0 for deactivating the + * callback. If inRelativeToNow is 1, times are from the time of this call; + * otherwise they are from the time the callback was last called (or the time + * it was registered if it has never been called. + * + */ +XPLM_API void XPLMSetFlightLoopCallbackInterval( + XPLMFlightLoop_f inFlightLoop, + float inInterval, + int inRelativeToNow, + void * inRefcon); + +#if defined(XPLM210) +/* + * XPLMCreateFlightLoop + * + * This routine creates a flight loop callback and returns its ID. The flight + * loop callback is created using the input param struct, and is inited to be + * unscheduled. + * + */ +XPLM_API XPLMFlightLoopID XPLMCreateFlightLoop( + XPLMCreateFlightLoop_t * inParams); +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMDestroyFlightLoop + * + * This routine destroys a flight loop callback by ID. Only call it on flight + * loops created with the newer XPLMCreateFlightLoop API. + * + */ +XPLM_API void XPLMDestroyFlightLoop( + XPLMFlightLoopID inFlightLoopID); +#endif /* XPLM210 */ + +#if defined(XPLM210) +/* + * XPLMScheduleFlightLoop + * + * This routine schedules a flight loop callback for future execution. If + * inInterval is negative, it is run in a certain number of frames based on + * the absolute value of the input. If the interval is positive, it is a + * duration in seconds. + * + * If inRelativeToNow is true, ties are interpretted relative to the time this + * routine is called; otherwise they are relative to the last call time or the + * time the flight loop was registered (if never called). + * + */ +XPLM_API void XPLMScheduleFlightLoop( + XPLMFlightLoopID inFlightLoopID, + float inInterval, + int inRelativeToNow); +#endif /* XPLM210 */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMScenery.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMScenery.h new file mode 100644 index 0000000..452bac9 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMScenery.h @@ -0,0 +1,450 @@ +#ifndef _XPLMScenery_h_ +#define _XPLMScenery_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMScenery + ***************************************************************************/ +/* + * This package contains APIs to interact with X-Plane's scenery system. + * + */ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if defined(XPLM200) +/*************************************************************************** + * Terrain Y-Testing + ***************************************************************************/ +/* + * The Y-testing API allows you to locate the physical scenery mesh. This + * would be used to place dynamic graphics on top of the ground in a plausible + * way or do physics interactions. + * + * The Y-test API works via probe objects, which are allocated by your plugin + * and used to query terrain. Probe objects exist both to capture which + * algorithm you have requested (see probe types) and also to cache query + * information. + * + * Performance Guidelines + * ---------------------- + * + * It is generally faster to use the same probe for nearby points and + * different probes for different points. Try not to allocate more than + * "hundreds" of probes at most. Share probes if you need more. Generally, + * probing operations are expensive, and should be avoided via caching when + * possible. + * + * Y testing returns a location on the terrain, a normal vectory, and a + * velocity vector. The normal vector tells you the slope of the terrain at + * that point. The velocity vector tells you if that terrain is moving (and is + * in meters/second). For example, if your Y test hits the aircraft carrier + * deck, this tells you the velocity of that point on the deck. + * + * Note: the Y-testing API is limited to probing the loaded scenery area, + * which is approximately 300x300 km in X-Plane 9. Probes outside this area + * will return the height of a 0 MSL sphere. + * + */ + + +/* + * XPLMProbeType + * + * XPLMProbeType defines the type of terrain probe - each probe has a + * different algorithm. (Only one type of probe is provided right now, but + * future APIs will expose more flexible or poewrful or useful probes. + * + */ +enum { + /* The Y probe gives you the location of the tallest physical scenery along * + * the Y axis going through the queried point. */ + xplm_ProbeY = 0, + + +}; +typedef int XPLMProbeType; + +/* + * XPLMProbeResult + * + * Probe results - possible results from a probe query. + * + */ +enum { + /* The probe hit terrain and returned valid values. */ + xplm_ProbeHitTerrain = 0, + + /* An error in the API call. Either the probe struct size is bad, or the * + * probe is invalid or the type is mismatched for the specific query call. */ + xplm_ProbeError = 1, + + /* The probe call succeeded but there is no terrain under this point (perhaps * + * it is off the side of the planet?) */ + xplm_ProbeMissed = 2, + + +}; +typedef int XPLMProbeResult; + +/* + * XPLMProbeRef + * + * An XPLMProbeRef is an opaque handle to a probe, used for querying the + * terrain. + * + */ +typedef void * XPLMProbeRef; + +/* + * XPLMProbeInfo_t + * + * XPLMProbeInfo_t contains the results of a probe call. Make sure to set + * structSize to the size of the struct before using it. + * + */ +typedef struct { + /* Size of structure in bytes - always set this before calling the XPLM. */ + int structSize; + /* Resulting X location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationX; + /* Resulting Y location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationY; + /* Resulting Z location of the terrain point we hit, in local OpenGL * + * coordinates. */ + float locationZ; + /* X component of the normal vector to the terrain we found. */ + float normalX; + /* Y component of the normal vector to the terrain we found. */ + float normalY; + /* Z component of the normal vector to the terrain we found. */ + float normalZ; + /* X component of the velocity vector of the terrain we found. */ + float velocityX; + /* Y component of the velocity vector of the terrain we found. */ + float velocityY; + /* Z component of the velocity vector of the terrain we found. */ + float velocityZ; + /* Tells if the surface we hit is water (otherwise it is land). */ + int is_wet; +} XPLMProbeInfo_t; + +/* + * XPLMCreateProbe + * + * Creates a new probe object of a given type and returns. + * + */ +XPLM_API XPLMProbeRef XPLMCreateProbe( + XPLMProbeType inProbeType); + +/* + * XPLMDestroyProbe + * + * Deallocates an existing probe object. + * + */ +XPLM_API void XPLMDestroyProbe( + XPLMProbeRef inProbe); + +/* + * XPLMProbeTerrainXYZ + * + * Probes the terrain. Pass in the XYZ coordinate of the probe point, a probe + * object, and an XPLMProbeInfo_t struct that has its structSize member set + * properly. Other fields are filled in if we hit terrain, and a probe result + * is returned. + * + */ +XPLM_API XPLMProbeResult XPLMProbeTerrainXYZ( + XPLMProbeRef inProbe, + float inX, + float inY, + float inZ, + XPLMProbeInfo_t * outInfo); + +#endif /* XPLM200 */ +#if defined(XPLM300) +/*************************************************************************** + * Magnetic Variation + ***************************************************************************/ +/* + * Use the magnetic variation (more properly, the "magnetic declination") API + * to find the offset of magnetic north from true north at a given latitude + * and longitude within the simulator. + * + * In the real world, the Earth's magnetic field is irregular, such that true + * north (the direction along a meridian toward the north pole) does not + * necessarily match what a magnetic compass shows as north. + * + * Using this API ensures that you present the same offsets to users as + * X-Plane's built-in instruments. + * + */ + + +/* + * XPLMGetMagneticVariation + * + * Returns X-Plane's simulated magnetic variation (declination) at the + * indication latitude and longitude. + * + */ +XPLM_API float XPLMGetMagneticVariation( + double latitude, + double longitude); + +/* + * XPLMDegTrueToDegMagnetic + * + * Converts a heading in degrees relative to true north into a value relative + * to magnetic north at the user's current location. + * + */ +XPLM_API float XPLMDegTrueToDegMagnetic( + float headingDegreesTrue); + +/* + * XPLMDegMagneticToDegTrue + * + * Converts a heading in degrees relative to magnetic north at the user's + * current location into a value relative to true north. + * + */ +XPLM_API float XPLMDegMagneticToDegTrue( + float headingDegreesMagnetic); + +#endif /* XPLM300 */ +/*************************************************************************** + * Object Drawing + ***************************************************************************/ +/* + * The object drawing routines let you load and draw X-Plane OBJ files. + * Objects are loaded by file path and managed via an opaque handle. X-Plane + * naturally reference counts objects, so it is important that you balance + * every successful call to XPLMLoadObject with a call to XPLMUnloadObject! + * + */ + + +#if defined(XPLM200) +/* + * XPLMObjectRef + * + * An XPLMObjectRef is a opaque handle to an .obj file that has been loaded + * into memory. + * + */ +typedef void * XPLMObjectRef; +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMDrawInfo_t + * + * The XPLMDrawInfo_t structure contains positioning info for one object that + * is to be drawn. Be sure to set structSize to the size of the structure for + * future expansion. + * + */ +typedef struct { + /* Set this to the size of this structure! */ + int structSize; + /* X location of the object in local coordinates. */ + float x; + /* Y location of the object in local coordinates. */ + float y; + /* Z location of the object in local coordinates. */ + float z; + /* Pitch in degres to rotate the object, positive is up. */ + float pitch; + /* Heading in local coordinates to rotate the object, clockwise. */ + float heading; + /* Roll to rotate the object. */ + float roll; +} XPLMDrawInfo_t; +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* + * XPLMObjectLoaded_f + * + * You provide this callback when loading an object asynchronously; it will be + * called once the object is loaded. Your refcon is passed back. The object + * ref passed in is the newly loaded object (ready for use) or NULL if an + * error occured. + * + * If your plugin is disabled, this callback will be delivered as soon as the + * plugin is re-enabled. If your plugin is unloaded before this callback is + * ever called, the SDK will release the object handle for you. + * + */ +typedef void (* XPLMObjectLoaded_f)( + XPLMObjectRef inObject, + void * inRefcon); +#endif /* XPLM210 */ + +#if defined(XPLM200) +/* + * XPLMLoadObject + * + * This routine loads an OBJ file and returns a handle to it. If X-Plane has + * already loaded the object, the handle to the existing object is returned. + * Do not assume you will get the same handle back twice, but do make sure to + * call unload once for every load to avoid "leaking" objects. The object will + * be purged from memory when no plugins and no scenery are using it. + * + * The path for the object must be relative to the X-System base folder. If + * the path is in the root of the X-System folder you may need to prepend ./ + * to it; loading objects in the root of the X-System folder is STRONGLY + * discouraged - your plugin should not dump art resources in the root folder! + * + * XPLMLoadObject will return NULL if the object cannot be loaded (either + * because it is not found or the file is misformatted). This routine will + * load any object that can be used in the X-Plane scenery system. + * + * It is important that the datarefs an object uses for animation already be + * loaded before you load the object. For this reason it may be necessary to + * defer object loading until the sim has fully started. + * + */ +XPLM_API XPLMObjectRef XPLMLoadObject( + const char * inPath); +#endif /* XPLM200 */ + +#if defined(XPLM210) +/* + * XPLMLoadObjectAsync + * + * This routine loads an object asynchronously; control is returned to you + * immediately while X-Plane loads the object. The sim will not stop flying + * while the object loads. For large objects, it may be several seconds before + * the load finishes. + * + * You provide a callback function that is called once the load has completed. + * Note that if the object cannot be loaded, you will not find out until the + * callback function is called with a NULL object handle. + * + * There is no way to cancel an asynchronous object load; you must wait for + * the load to complete and then release the object if it is no longer + * desired. + * + */ +XPLM_API void XPLMLoadObjectAsync( + const char * inPath, + XPLMObjectLoaded_f inCallback, + void * inRefcon); +#endif /* XPLM210 */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMDrawObjects + * + * __Deprecation Warning__: use XPLMInstancing to draw 3-d objects by creating + * instances, rather than these APIs from draw callbacks. + * + * XPLMDrawObjects draws an object from an OBJ file one or more times. You + * pass in the object and an array of XPLMDrawInfo_t structs, one for each + * place you would like the object to be drawn. + * + * X-Plane will attempt to cull the objects based on LOD and visibility, and + * will pick the appropriate LOD. + * + * Lighting is a boolean; pass 1 to show the night version of object with + * night-only lights lit up. Pass 0 to show the daytime version of the object. + * + * earth_relative controls the coordinate system. If this is 1, the rotations + * you specify are applied to the object after its coordinate system is + * transformed from local to earth-relative coordinates -- that is, an object + * with no rotations will point toward true north and the Y axis will be up + * against gravity. If this is 0, the object is drawn with your rotations from + * local coordanates -- that is, an object with no rotations is drawn pointing + * down the -Z axis and the Y axis of the object matches the local coordinate + * Y axis. + * + */ +XPLM_API void XPLMDrawObjects( + XPLMObjectRef inObject, + int inCount, + XPLMDrawInfo_t * inLocations, + int lighting, + int earth_relative); +#endif /* XPLM_DEPRECATED */ + +#if defined(XPLM200) +/* + * XPLMUnloadObject + * + * This routine marks an object as no longer being used by your plugin. + * Objects are reference counted: once no plugins are using an object, it is + * purged from memory. Make sure to call XPLMUnloadObject once for each + * successful call to XPLMLoadObject. + * + */ +XPLM_API void XPLMUnloadObject( + XPLMObjectRef inObject); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/*************************************************************************** + * Library Access + ***************************************************************************/ +/* + * The library access routines allow you to locate scenery objects via the + * X-Plane library system. Right now library access is only provided for + * objects, allowing plugin-drawn objects to be extended using the library + * system. + * + */ + + +/* + * XPLMLibraryEnumerator_f + * + * An XPLMLibraryEnumerator_f is a callback you provide that is called once + * for each library element that is located. The returned paths will be + * relative to the X-System folder. + * + */ +typedef void (* XPLMLibraryEnumerator_f)( + const char * inFilePath, + void * inRef); + +/* + * XPLMLookupObjects + * + * This routine looks up a virtual path in the library system and returns all + * matching elements. You provide a callback - one virtual path may match many + * objects in the library. XPLMLookupObjects returns the number of objects + * found. + * + * The latitude and longitude parameters specify the location the object will + * be used. The library system allows for scenery packages to only provide + * objects to certain local locations. Only objects that are allowed at the + * latitude/longitude you provide will be returned. + * + */ +XPLM_API int XPLMLookupObjects( + const char * inPath, + float inLatitude, + float inLongitude, + XPLMLibraryEnumerator_f enumerator, + void * ref); + +#endif /* XPLM200 */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMUtilities.h b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMUtilities.h new file mode 100644 index 0000000..bec319e --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/CHeaders/XPLM/XPLMUtilities.h @@ -0,0 +1,970 @@ +#ifndef _XPLMUtilities_h_ +#define _XPLMUtilities_h_ + +/* + * Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + * license.txt for usage. X-Plane SDK Version: 2.1.1 + * + */ + +/*************************************************************************** + * XPLMUtilities + ***************************************************************************/ + +#include "XPLMDefs.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/*************************************************************************** + * FILE UTILITIES + ***************************************************************************/ +/* + * The XPLMUtilities file APIs provide some basic file and path functions for + * use with X-Plane. + * + * Directory Separators + * -------------------- + * + * The XPLM has two modes it can work in: + * + * * X-Plane native paths: all paths are UTF8 strings, using the unix forward + * slash (/) as the directory separating character. In native path mode, + * you use the same path format for all three operating systems. + * + * * Legacy OS paths: the directroy separator is \ for Windows, : for OS X, + * and / for Linux; OS paths are encoded in MacRoman for OS X using legacy + * HFS conventions, use the application code page for multi-byte encoding + * on Unix using DOS path conventions, and use UTF-8 for Linux. + * + * While legacy OS paths are the default, we strongly encourage you to opt in + * to native paths using the XPLMEnableFeature API. + * + * * All OS X plugins should enable native paths all of the time; if you do + * not do this, you will have to convert all paths back from HFS to Unix + * (and deal with MacRoman) - code written using native paths and the C + * file APIs "just works" on OS X. + * + * * For Linux plugins, there is no difference between the two encodings. + * + * * Windows plugins will need to convert the UTF8 file paths to UTF16 for + * use with the "wide" APIs. While it might seem tempting to stick with + * legacy OS paths (and just use the "ANSI" Windows APIs), X-Plane is fully + * unicode-capable, and will often be installed in paths where the user's + * directories have no ACP encoding. + * + * Full and Relative Paths + * ----------------------- + * + * Some of these APIs use full paths, but others use paths relative to the + * user's X-Plane installation. This is documented on a per-API basis. + * + */ + + +#if defined(XPLM200) +/* + * XPLMDataFileType + * + * These enums define types of data files you can load or unload using the + * SDK. + * + */ +enum { + /* A situation (.sit) file, which starts off a flight in a given * + * configuration. */ + xplm_DataFile_Situation = 1, + + /* A situation movie (.smo) file, which replays a past flight. */ + xplm_DataFile_ReplayMovie = 2, + + +}; +typedef int XPLMDataFileType; +#endif /* XPLM200 */ + +/* + * XPLMGetSystemPath + * + * This function returns the full path to the X-System folder. Note that this + * is a directory path, so it ends in a trailing : or /. + * + * The buffer you pass should be at least 512 characters long. The path is + * returned using the current native or OS path conventions. + * + */ +XPLM_API void XPLMGetSystemPath( + char * outSystemPath); + +/* + * XPLMGetPrefsPath + * + * This routine returns a full path to a file that is within X-Plane's + * preferences directory. (You should remove the file name back to the last + * directory separator to get the preferences directory using + * XPLMExtractFileAndPath.) + * + * The buffer you pass should be at least 512 characters long. The path is + * returned using the current native or OS path conventions. + * + */ +XPLM_API void XPLMGetPrefsPath( + char * outPrefsPath); + +/* + * XPLMGetDirectorySeparator + * + * This routine returns a string with one char and a null terminator that is + * the directory separator for the current platform. This allows you to write + * code that concatinates directory paths without having to #ifdef for + * platform. The character returned will reflect the current file path mode. + * + */ +XPLM_API const char * XPLMGetDirectorySeparator(void); + +/* + * XPLMExtractFileAndPath + * + * Given a full path to a file, this routine separates the path from the file. + * If the path is a partial directory (e.g. ends in : or \) the trailing + * directory separator is removed. This routine works in-place; a pointer to + * the file part of the buffer is returned; the original buffer still starts + * with the path and is null terminated with no trailing separator. + * + */ +XPLM_API char * XPLMExtractFileAndPath( + char * inFullPath); + +/* + * XPLMGetDirectoryContents + * + * This routine returns a list of files in a directory (specified by a full + * path, no trailing : or \). The output is returned as a list of NULL + * terminated strings. An index array (if specified) is filled with pointers + * into the strings. The last file is indicated by a zero-length string (and + * NULL in the indices). This routine will return 1 if you had capacity for + * all files or 0 if you did not. You can also skip a given number of files. + * + * * inDirectoryPath - a null terminated C string containing the full path to + * the directory with no trailing directory char. + * + * * inFirstReturn - the zero-based index of the first file in the directory + * to return. (Usually zero to fetch all in one pass.) + * + * * outFileNames - a buffer to receive a series of sequential null + * terminated C-string file names. A zero-length C string will be appended + * to the very end. + * + * * inFileNameBufSize - the size of the file name buffer in bytes. + * + * * outIndices - a pointer to an array of character pointers that will + * become an index into the directory. The last file will be followed by a + * NULL value. Pass NULL if you do not want indexing information. + * + * * inIndexCount - the max size of the index in entries. + * + * * outTotalFiles - if not NULL, this is filled in with the number of files + * in the directory. + * + * * outReturnedFiles - if not NULL, the number of files returned by this + * iteration. + * + * Return value: 1 if all info could be returned, 0 if there was a buffer + * overrun. + * + * WARNING: Before X-Plane 7 this routine did not properly iterate through + * directories. If X-Plane + * 6 compatibility is needed, use your own code to iterate directories. + * + */ +XPLM_API int XPLMGetDirectoryContents( + const char * inDirectoryPath, + int inFirstReturn, + char * outFileNames, + int inFileNameBufSize, + char ** outIndices, /* Can be NULL */ + int inIndexCount, + int * outTotalFiles, /* Can be NULL */ + int * outReturnedFiles); /* Can be NULL */ + +#if defined(XPLM200) +/* + * XPLMLoadDataFile + * + * Loads a data file of a given type. Paths must be relative to the X-System + * folder. To clear the replay, pass a NULL file name (this is only valid with + * replay movies, not sit files). + * + */ +XPLM_API int XPLMLoadDataFile( + XPLMDataFileType inFileType, + const char * inFilePath); /* Can be NULL */ +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMSaveDataFile + * + * Saves the current situation or replay; paths are relative to the X-System + * folder. + * + */ +XPLM_API int XPLMSaveDataFile( + XPLMDataFileType inFileType, + const char * inFilePath); +#endif /* XPLM200 */ + +/*************************************************************************** + * X-PLANE MISC + ***************************************************************************/ + +/* + * XPLMHostApplicationID + * + * While the plug-in SDK is only accessible to plugins running inside X-Plane, + * the original authors considered extending the API to other applications + * that shared basic infrastructure with X-Plane. These enumerations are + * hold-overs from that original roadmap; all values other than X-Plane are + * deprecated. Your plugin should never need this enumeration. + * + */ +enum { + xplm_Host_Unknown = 0, + + xplm_Host_XPlane = 1, + +#if defined(XPLM_DEPRECATED) + xplm_Host_PlaneMaker = 2, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_WorldMaker = 3, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_Briefer = 4, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_PartMaker = 5, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_YoungsMod = 6, + +#endif /* XPLM_DEPRECATED */ +#if defined(XPLM_DEPRECATED) + xplm_Host_XAuto = 7, + +#endif /* XPLM_DEPRECATED */ + +}; +typedef int XPLMHostApplicationID; + +/* + * XPLMLanguageCode + * + * These enums define what language the sim is running in. These enumerations + * do not imply that the sim can or does run in all of these languages; they + * simply provide a known encoding in the event that a given sim version is + * localized to a certain language. + * + */ +enum { + xplm_Language_Unknown = 0, + + xplm_Language_English = 1, + + xplm_Language_French = 2, + + xplm_Language_German = 3, + + xplm_Language_Italian = 4, + + xplm_Language_Spanish = 5, + + xplm_Language_Korean = 6, + +#if defined(XPLM200) + xplm_Language_Russian = 7, + +#endif /* XPLM200 */ +#if defined(XPLM200) + xplm_Language_Greek = 8, + +#endif /* XPLM200 */ +#if defined(XPLM200) + xplm_Language_Japanese = 9, + +#endif /* XPLM200 */ +#if defined(XPLM300) + xplm_Language_Chinese = 10, + +#endif /* XPLM300 */ + +}; +typedef int XPLMLanguageCode; + +#if defined(XPLM200) +/* + * XPLMError_f + * + * An XPLM error callback is a function that you provide to receive debugging + * information from the plugin SDK. See XPLMSetErrorCallback for more + * information. NOTE: for the sake of debugging, your error callback will be + * called even if your plugin is not enabled, allowing you to receive debug + * info in your XPluginStart and XPluginStop callbacks. To avoid causing logic + * errors in the management code, do not call any other plugin routines from + * your error callback - it is only meant for catching errors in the + * debugging. + * + */ +typedef void (* XPLMError_f)( + const char * inMessage); +#endif /* XPLM200 */ + +#if defined(XPLM_DEPRECATED) +/* + * XPLMInitialized + * + * Deprecated: This function returns 1 if X-Plane has properly initialized the + * plug-in system. If this routine returns 0, many XPLM functions will not + * work. + * + * NOTE: because plugins are always called from within the XPLM, there is no + * need to check for initialization; it will always return 1. This routine is + * deprecated - you do not need to check it before continuing within your + * plugin. + * + */ +XPLM_API int XPLMInitialized(void); +#endif /* XPLM_DEPRECATED */ + +/* + * XPLMGetVersions + * + * This routine returns the revision of both X-Plane and the XPLM DLL. All + * versions are three-digit decimal numbers (e.g. 606 for version 6.06 of + * X-Plane); the current revision of the XPLM is 200 (2.00). This routine also + * returns the host ID of the app running us. + * + * The most common use of this routine is to special-case around X-Plane + * version-specific behavior. + * + */ +XPLM_API void XPLMGetVersions( + int * outXPlaneVersion, + int * outXPLMVersion, + XPLMHostApplicationID * outHostID); + +/* + * XPLMGetLanguage + * + * This routine returns the langauge the sim is running in. + * + */ +XPLM_API XPLMLanguageCode XPLMGetLanguage(void); + +#if defined(XPLM200) +/* + * XPLMFindSymbol + * + * This routine will attempt to find the symbol passed in the inString + * parameter. If the symbol is found a pointer the function is returned, + * othewise the function will return NULL. + * + * You can use XPLMFindSymbol to utilize newer SDK API features without + * requiring newer versions of the SDK (and X-Plane) as your minimum X-Plane + * version as follows: + * + * * Define the XPLMnnn macro to the minimum required XPLM version you will + * ship with (e.g. XPLM210 for X-Plane 10 compatibility). + * + * * Use XPLMGetVersions and XPLMFindSymbol to detect that the host sim is + * new enough to use new functions and resolve function pointers. + * + * * Conditionally use the new functions if and only if XPLMFindSymbol only + * returns a non- NULL pointer. + * + * Warning: you should always check the XPLM API version as well as the + * results of XPLMFindSymbol to determine if funtionality is safe to use. + * + * To use functionality via XPLMFindSymbol you will need to copy your own + * definitions of the X-Plane API prototypes and cast the returned pointer to + * the correct type. + * + */ +XPLM_API void * XPLMFindSymbol( + const char * inString); +#endif /* XPLM200 */ + +#if defined(XPLM200) +/* + * XPLMSetErrorCallback + * + * XPLMSetErrorCallback installs an error-reporting callback for your plugin. + * Normally the plugin system performs minimum diagnostics to maximize + * performance. When you install an error callback, you will receive calls due + * to certain plugin errors, such as passing bad parameters or incorrect data. + * + * Important: the error callback determines *programming* errors, e.g. bad API + * parameters. Every error that is returned by the error callback represents a + * mistake in your plugin that you should fix. Error callbacks are not used to + * report expected run-time problems (e.g. disk I/O errors). + * + * The intention is for you to install the error callback during debug + * sections and put a break-point inside your callback. This will cause you to + * break into the debugger from within the SDK at the point in your plugin + * where you made an illegal call. + * + * Installing an error callback may activate error checking code that would + * not normally run, and this may adversely affect performance, so do not + * leave error callbacks installed in shipping plugins. Since the only useful + * response to an error is to change code, error callbacks are not useful "in + * the field". + * + */ +XPLM_API void XPLMSetErrorCallback( + XPLMError_f inCallback); +#endif /* XPLM200 */ + +/* + * XPLMDebugString + * + * This routine outputs a C-style string to the Log.txt file. The file is + * immediately flushed so you will not lose data. (This does cause a + * performance penalty.) + * + * Please do *not* leave routine diagnostic logging enabled in your shipping + * plugin. The X-Plane Log file is shared by X-Plane and every plugin in the + * system, and plugins that (when functioning normally) print verbose log + * output make it difficult for developers to find error conditions from other + * parts of the system. + * + */ +XPLM_API void XPLMDebugString( + const char * inString); + +/* + * XPLMSpeakString + * + * This function displays the string in a translucent overlay over the current + * display and also speaks the string if text-to-speech is enabled. The string + * is spoken asynchronously, this function returns immediately. This function + * may not speak or print depending on user preferences. + * + */ +XPLM_API void XPLMSpeakString( + const char * inString); + +/* + * XPLMGetVirtualKeyDescription + * + * Given a virtual key code (as defined in XPLMDefs.h) this routine returns a + * human-readable string describing the character. This routine is provided + * for showing users what keyboard mappings they have set up. The string may + * read 'unknown' or be a blank or NULL string if the virtual key is unknown. + * + */ +XPLM_API const char * XPLMGetVirtualKeyDescription( + char inVirtualKey); + +/* + * XPLMReloadScenery + * + * XPLMReloadScenery reloads the current set of scenery. You can use this + * function in two typical ways: simply call it to reload the scenery, picking + * up any new installed scenery, .env files, etc. from disk. Or, change the + * lat/ref and lon/ref data refs and then call this function to shift the + * scenery environment. This routine is equivalent to picking "reload + * scenery" from the developer menu. + * + */ +XPLM_API void XPLMReloadScenery(void); + +#if defined(XPLM200) +/*************************************************************************** + * X-PLANE COMMAND MANAGEMENT + ***************************************************************************/ +/* + * The command management APIs let plugins interact with the command-system in + * X-Plane, the abstraction behind keyboard presses and joystick buttons. This + * API lets you create new commands and modify the behavior (or get + * notification) of existing ones. + * + * X-Plane Command Phases + * ---------------------- + * + * X-Plane commands are not instantaneous; they operate over a duration. + * (Think of a joystick button press - you can press, hold down, and then + * release the joystick button; X-Plane commands model this entire process.) + * + * An X-Plane command consists of three phases: a beginning, continuous + * repetition, and an ending. The command may be repeated zero times in its + * duration, followed by one command ending. Command begin and end messges are + * balanced, but a command may be bound to more than one event source (e.g. a + * keyboard key and a joystick button), in which case you may receive a second + * begin during before any end). + * + * When you issue commands in the plugin system, you *must* balance every call + * to XPLMCommandBegin with a call to XPLMCommandEnd with the same command + * reference. + * + * Command Behavior Modification + * ----------------------------- + * + * You can register a callback to handle a command either before or after + * X-Plane does; if you receive the command before X-Plane you have the option + * to either let X-Plane handle the command or hide the command from X-Plane. + * This lets plugins both augment commands and replace them. + * + * If you register for an existing command, be sure that you are *consistent* + * in letting X-Plane handle or not handle the command; you are responsible + * for passing a *balanced* number of begin and end messages to X-Plane. (E.g. + * it is not legal to pass all the begin messages to X-Plane but hide all the + * end messages). + * + */ + + +/* + * XPLMCommandPhase + * + * The phases of a command. + * + */ +enum { + /* The command is being started. */ + xplm_CommandBegin = 0, + + /* The command is continuing to execute. */ + xplm_CommandContinue = 1, + + /* The command has ended. */ + xplm_CommandEnd = 2, + + +}; +typedef int XPLMCommandPhase; + +/* + * XPLMCommandRef + * + * A command ref is an opaque identifier for an X-Plane command. Command + * references stay the same for the life of your plugin but not between + * executions of X-Plane. Command refs are used to execute commands, create + * commands, and create callbacks for particular commands. + * + * Note that a command is not "owned" by a particular plugin. Since many + * plugins may participate in a command's execution, the command does not go + * away if the plugin that created it is unloaded. + * + */ +typedef void * XPLMCommandRef; + +/* + * XPLMCommandCallback_f + * + * A command callback is a function in your plugin that is called when a + * command is pressed. Your callback receives the command reference for the + * particular command, the phase of the command that is executing, and a + * reference pointer that you specify when registering the callback. + * + * Your command handler should return 1 to let processing of the command + * continue to other plugins and X-Plane, or 0 to halt processing, potentially + * bypassing X-Plane code. + * + */ +typedef int (* XPLMCommandCallback_f)( + XPLMCommandRef inCommand, + XPLMCommandPhase inPhase, + void * inRefcon); + +/* + * XPLMFindCommand + * + * XPLMFindCommand looks up a command by name, and returns its command + * reference or NULL if the command does not exist. + * + */ +XPLM_API XPLMCommandRef XPLMFindCommand( + const char * inName); + +/* + * XPLMCommandBegin + * + * XPLMCommandBegin starts the execution of a command, specified by its + * command reference. The command is "held down" until XPLMCommandEnd is + * called. You must balance each XPLMCommandBegin call with an XPLMCommandEnd + * call. + * + */ +XPLM_API void XPLMCommandBegin( + XPLMCommandRef inCommand); + +/* + * XPLMCommandEnd + * + * XPLMCommandEnd ends the execution of a given command that was started with + * XPLMCommandBegin. You must not issue XPLMCommandEnd for a command you did + * not begin. + * + */ +XPLM_API void XPLMCommandEnd( + XPLMCommandRef inCommand); + +/* + * XPLMCommandOnce + * + * This executes a given command momentarily, that is, the command begins and + * ends immediately. This is the equivalent of calling XPLMCommandBegin() and + * XPLMCommandEnd() back ot back. + * + */ +XPLM_API void XPLMCommandOnce( + XPLMCommandRef inCommand); + +/* + * XPLMCreateCommand + * + * XPLMCreateCommand creates a new command for a given string. If the command + * already exists, the existing command reference is returned. The description + * may appear in user interface contexts, such as the joystick configuration + * screen. + * + */ +XPLM_API XPLMCommandRef XPLMCreateCommand( + const char * inName, + const char * inDescription); + +/* + * XPLMRegisterCommandHandler + * + * XPLMRegisterCommandHandler registers a callback to be called when a command + * is executed. You provide a callback with a reference pointer. + * + * If inBefore is true, your command handler callback will be executed before + * X-Plane executes the command, and returning 0 from your callback will + * disable X-Plane's processing of the command. If inBefore is false, your + * callback will run after X-Plane. (You can register a single callback both + * before and after a command.) + * + */ +XPLM_API void XPLMRegisterCommandHandler( + XPLMCommandRef inComand, + XPLMCommandCallback_f inHandler, + int inBefore, + void * inRefcon); + +/* + * XPLMUnregisterCommandHandler + * + * XPLMUnregisterCommandHandler removes a command callback registered with + * XPLMRegisterCommandHandler. + * + */ +XPLM_API void XPLMUnregisterCommandHandler( + XPLMCommandRef inComand, + XPLMCommandCallback_f inHandler, + int inBefore, + void * inRefcon); + +#endif /* XPLM200 */ +#if defined(XPLM_DEPRECATED) +/*************************************************************************** + * X-PLANE USER INTERACTION + ***************************************************************************/ +/* + * WARNING: The legacy user interaction API is deprecated; while it was the + * only way to run commands in X-Plane 6,7 and 8, it is obsolete, and was + * replaced by the command system API in X-Plane 9. You should not use this + * API; replace any of the calls below with XPLMCommand invocations based on + * persistent command strings. The documentation that follows is for historic + * reference only. + * + * The legacy user interaction APIs let you simulate commands the user can do + * with a joystick, keyboard etc. Note that it is generally safer for future + * compatibility to use one of these commands than to manipulate the + * underlying sim data. + * + */ + + +/* + * XPLMCommandKeyID + * + * These enums represent all the keystrokes available within X-Plane. They can + * be sent to X-Plane directly. For example, you can reverse thrust using + * these enumerations. + * + */ +enum { + xplm_key_pause=0, + xplm_key_revthrust, + xplm_key_jettison, + xplm_key_brakesreg, + xplm_key_brakesmax, + xplm_key_gear, + xplm_key_timedn, + xplm_key_timeup, + xplm_key_fadec, + xplm_key_otto_dis, + xplm_key_otto_atr, + xplm_key_otto_asi, + xplm_key_otto_hdg, + xplm_key_otto_gps, + xplm_key_otto_lev, + xplm_key_otto_hnav, + xplm_key_otto_alt, + xplm_key_otto_vvi, + xplm_key_otto_vnav, + xplm_key_otto_nav1, + xplm_key_otto_nav2, + xplm_key_targ_dn, + xplm_key_targ_up, + xplm_key_hdgdn, + xplm_key_hdgup, + xplm_key_barodn, + xplm_key_baroup, + xplm_key_obs1dn, + xplm_key_obs1up, + xplm_key_obs2dn, + xplm_key_obs2up, + xplm_key_com1_1, + xplm_key_com1_2, + xplm_key_com1_3, + xplm_key_com1_4, + xplm_key_nav1_1, + xplm_key_nav1_2, + xplm_key_nav1_3, + xplm_key_nav1_4, + xplm_key_com2_1, + xplm_key_com2_2, + xplm_key_com2_3, + xplm_key_com2_4, + xplm_key_nav2_1, + xplm_key_nav2_2, + xplm_key_nav2_3, + xplm_key_nav2_4, + xplm_key_adf_1, + xplm_key_adf_2, + xplm_key_adf_3, + xplm_key_adf_4, + xplm_key_adf_5, + xplm_key_adf_6, + xplm_key_transpon_1, + xplm_key_transpon_2, + xplm_key_transpon_3, + xplm_key_transpon_4, + xplm_key_transpon_5, + xplm_key_transpon_6, + xplm_key_transpon_7, + xplm_key_transpon_8, + xplm_key_flapsup, + xplm_key_flapsdn, + xplm_key_cheatoff, + xplm_key_cheaton, + xplm_key_sbrkoff, + xplm_key_sbrkon, + xplm_key_ailtrimL, + xplm_key_ailtrimR, + xplm_key_rudtrimL, + xplm_key_rudtrimR, + xplm_key_elvtrimD, + xplm_key_elvtrimU, + xplm_key_forward, + xplm_key_down, + xplm_key_left, + xplm_key_right, + xplm_key_back, + xplm_key_tower, + xplm_key_runway, + xplm_key_chase, + xplm_key_free1, + xplm_key_free2, + xplm_key_spot, + xplm_key_fullscrn1, + xplm_key_fullscrn2, + xplm_key_tanspan, + xplm_key_smoke, + xplm_key_map, + xplm_key_zoomin, + xplm_key_zoomout, + xplm_key_cycledump, + xplm_key_replay, + xplm_key_tranID, + xplm_key_max +}; +typedef int XPLMCommandKeyID; + +/* + * XPLMCommandButtonID + * + * These are enumerations for all of the things you can do with a joystick + * button in X-Plane. They currently match the buttons menu in the equipment + * setup dialog, but these enums will be stable even if they change in + * X-Plane. + * + */ +enum { + xplm_joy_nothing=0, + xplm_joy_start_all, + xplm_joy_start_0, + xplm_joy_start_1, + xplm_joy_start_2, + xplm_joy_start_3, + xplm_joy_start_4, + xplm_joy_start_5, + xplm_joy_start_6, + xplm_joy_start_7, + xplm_joy_throt_up, + xplm_joy_throt_dn, + xplm_joy_prop_up, + xplm_joy_prop_dn, + xplm_joy_mixt_up, + xplm_joy_mixt_dn, + xplm_joy_carb_tog, + xplm_joy_carb_on, + xplm_joy_carb_off, + xplm_joy_trev, + xplm_joy_trm_up, + xplm_joy_trm_dn, + xplm_joy_rot_trm_up, + xplm_joy_rot_trm_dn, + xplm_joy_rud_lft, + xplm_joy_rud_cntr, + xplm_joy_rud_rgt, + xplm_joy_ail_lft, + xplm_joy_ail_cntr, + xplm_joy_ail_rgt, + xplm_joy_B_rud_lft, + xplm_joy_B_rud_rgt, + xplm_joy_look_up, + xplm_joy_look_dn, + xplm_joy_look_lft, + xplm_joy_look_rgt, + xplm_joy_glance_l, + xplm_joy_glance_r, + xplm_joy_v_fnh, + xplm_joy_v_fwh, + xplm_joy_v_tra, + xplm_joy_v_twr, + xplm_joy_v_run, + xplm_joy_v_cha, + xplm_joy_v_fr1, + xplm_joy_v_fr2, + xplm_joy_v_spo, + xplm_joy_flapsup, + xplm_joy_flapsdn, + xplm_joy_vctswpfwd, + xplm_joy_vctswpaft, + xplm_joy_gear_tog, + xplm_joy_gear_up, + xplm_joy_gear_down, + xplm_joy_lft_brake, + xplm_joy_rgt_brake, + xplm_joy_brakesREG, + xplm_joy_brakesMAX, + xplm_joy_speedbrake, + xplm_joy_ott_dis, + xplm_joy_ott_atr, + xplm_joy_ott_asi, + xplm_joy_ott_hdg, + xplm_joy_ott_alt, + xplm_joy_ott_vvi, + xplm_joy_tim_start, + xplm_joy_tim_reset, + xplm_joy_ecam_up, + xplm_joy_ecam_dn, + xplm_joy_fadec, + xplm_joy_yaw_damp, + xplm_joy_art_stab, + xplm_joy_chute, + xplm_joy_JATO, + xplm_joy_arrest, + xplm_joy_jettison, + xplm_joy_fuel_dump, + xplm_joy_puffsmoke, + xplm_joy_prerotate, + xplm_joy_UL_prerot, + xplm_joy_UL_collec, + xplm_joy_TOGA, + xplm_joy_shutdown, + xplm_joy_con_atc, + xplm_joy_fail_now, + xplm_joy_pause, + xplm_joy_rock_up, + xplm_joy_rock_dn, + xplm_joy_rock_lft, + xplm_joy_rock_rgt, + xplm_joy_rock_for, + xplm_joy_rock_aft, + xplm_joy_idle_hilo, + xplm_joy_lanlights, + xplm_joy_max +}; +typedef int XPLMCommandButtonID; + +/* + * XPLMSimulateKeyPress + * + * This function simulates a key being pressed for X-Plane. The keystroke goes + * directly to X-Plane; it is never sent to any plug-ins. However, since this + * is a raw key stroke it may be mapped by the keys file or enter text into a + * field. + * + * Deprecated: use XPLMCommandOnce + * + */ +XPLM_API void XPLMSimulateKeyPress( + int inKeyType, + int inKey); + +/* + * XPLMCommandKeyStroke + * + * This routine simulates a command-key stroke. However, the keys are done by + * function, not by actual letter, so this function works even if the user has + * remapped their keyboard. Examples of things you might do with this include + * pausing the simulator. + * + * Deprecated: use XPLMCommandOnce + * + */ +XPLM_API void XPLMCommandKeyStroke( + XPLMCommandKeyID inKey); + +/* + * XPLMCommandButtonPress + * + * This function simulates any of the actions that might be taken by pressing + * a joystick button. However, this lets you call the command directly rather + * than have to know which button is mapped where. Important: you must release + * each button you press. The APIs are separate so that you can 'hold down' a + * button for a fixed amount of time. + * + * Deprecated: use XPLMCommandBegin. + * + */ +XPLM_API void XPLMCommandButtonPress( + XPLMCommandButtonID inButton); + +/* + * XPLMCommandButtonRelease + * + * This function simulates any of the actions that might be taken by pressing + * a joystick button. See XPLMCommandButtonPress. + * + * Deprecated: use XPLMCommandEnd. + * + */ +XPLM_API void XPLMCommandButtonRelease( + XPLMCommandButtonID inButton); + +#endif /* XPLM_DEPRECATED */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPStandardWidgets.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPStandardWidgets.pas new file mode 100644 index 0000000..d77f383 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPStandardWidgets.pas @@ -0,0 +1,470 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPStandardWidgets; +INTERFACE +{ + ## THEORY OF OPERATION + + The standard widgets are widgets built into the widgets library. While you + can gain access to the widget function that drives them, you generally use + them by calling XPCreateWidget and then listening for special messages, + etc. + + The standard widgets often send mesages to themselves when the user + performs an event; these messages are sent up the widget hierarchy until + they are handled. So you can add a widget proc directly to a push button + (for example) to intercept the message when it is clicked, or you can put + one widget proc on a window for all of the push buttons in the window. Most + of these messages contain the original widget ID as a parameter so you can + know which widget is messaging no matter who it is sent to. +} + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * MAIN WINDOW + ___________________________________________________________________________} +{ + The main window widget class provides a "window" as the user knows it. + These windows are dragable and can be selected. Use them to create floating + windows and non-modal dialogs. +} + + +CONST + xpWidgetClass_MainWindow = 1; + + { + Main Window Type Values + + These type values are used to control the appearance of a main window. + } + { The standard main window; pin stripes on XP7, metal frame on XP 6. } + xpMainWindowStyle_MainWindow = 0 +; + { A translucent dark gray window, like the one ATC messages appear in. } + xpMainWindowStyle_Translucent = 1 +; + + { + Main Window Properties + } + { This property specifies the type of window. Set to one of the main window } + { types above. } + xpProperty_MainWindowType = 1100 +; + { This property specifies whether the main window has close boxes in its } + { corners. } + xpProperty_MainWindowHasCloseBoxes = 1200 +; + + { + MainWindow Messages + } + { This message is sent when the close buttons are pressed for your window. } + xpMessage_CloseButtonPushed = 1200 +; + +{___________________________________________________________________________ + * SUB WINDOW + ___________________________________________________________________________} +{ + X-Plane dialogs are divided into separate areas; the sub window widgets + allow you to make these areas. Create one main window and place several + subwindows inside it. Then place your controls inside the subwindows. +} + + +CONST + xpWidgetClass_SubWindow = 2; + + { + SubWindow Type Values + + These values control the appearance of the subwindow. + } + { A panel that sits inside a main window. } + xpSubWindowStyle_SubWindow = 0 +; + { A screen that sits inside a panel for showing text information. } + xpSubWindowStyle_Screen = 2 +; + { A list view for scrolling lists. } + xpSubWindowStyle_ListView = 3 +; + + { + SubWindow Properties + } + { This property specifies the type of window. Set to one of the subwindow } + { types above. } + xpProperty_SubWindowType = 1200 +; + +{___________________________________________________________________________ + * BUTTON + ___________________________________________________________________________} +{ + The button class provides a number of different button styles and + behaviors, including push buttons, radio buttons, check boxes, etc. The + button label appears on or next to the button depending on the button's + appearance, or type. + + The button's behavior is a separate property that dictates who it hilights + and what kinds of messages it sends. Since behavior and type are different, + you can do strange things like make check boxes that act as push buttons or + push buttons with radio button behavior. + + In X-Plane 6 there were no check box graphics. The result is the following + behavior: in X-Plane + 6 all check box and radio buttons are round (radio-button style) buttons; + in X-Plane 7 they are all square (check-box style) buttons. In a future + version of X-Plane, the xpButtonBehavior enums will provide the correct + graphic (check box or radio button) giving the expected result. +} + + +CONST + xpWidgetClass_Button = 3; + + { + Button Types + + These define the visual appearance of buttons but not how they respond to + the mouse. + } + { This is a standard push button, like an 'OK' or 'Cancel' button in a dialog} + { box. } + xpPushButton = 0 +; + { A check box or radio button. Use this and the button behaviors below to } + { get the desired behavior. } + xpRadioButton = 1 +; + { A window close box. } + xpWindowCloseBox = 3 +; + { A small down arrow. } + xpLittleDownArrow = 5 +; + { A small up arrow. } + xpLittleUpArrow = 6 +; + + { + Button Behavior Values + + These define how the button responds to mouse clicks. + } + { Standard push button behavior. The button hilites while the mouse is } + { clicked over it and unhilites when the mouse is moved outside of it or } + { released. If the mouse is released over the button, the } + { xpMsg_PushButtonPressed message is sent. } + xpButtonBehaviorPushButton = 0 +; + { Check box behavior. The button immediately toggles its value when the mouse} + { is clicked and sends out a xpMsg_ButtonStateChanged message. } + xpButtonBehaviorCheckBox = 1 +; + { Radio button behavior. The button immediately sets its state to one and } + { sends out a xpMsg_ButtonStateChanged message if it was not already set to } + { one. You must turn off other radio buttons in a group in your code. } + xpButtonBehaviorRadioButton = 2 +; + + { + Button Properties + } + { This property sets the visual type of button. Use one of the button types } + { above. } + xpProperty_ButtonType = 1300 +; + { This property sets the button's behavior. Use one of the button behaviors } + { above. } + xpProperty_ButtonBehavior = 1301 +; + { This property tells whether a check box or radio button is "checked" or } + { not. Not used for push buttons. } + xpProperty_ButtonState = 1302 +; + + { + Button Messages + + These messages are sent by the button to itself and then up the widget + chain when the button is clicked. (You may intercept them by providing a + widget handler for the button itself or by providing a handler in a parent + widget.) + } + { This message is sent when the user completes a click and release in a } + { button with push button behavior. Parameter one of the message is the } + { widget ID of the button. This message is dispatched up the widget } + { hierarchy. } + xpMsg_PushButtonPressed = 1300 +; + { This message is sent when a button is clicked that has radio button or } + { check box behavior and its value changes. (Note that if the value changes } + { by setting a property you do not receive this message!) Parameter one is } + { the widget ID of the button, parameter 2 is the new state value, either } + { zero or one. This message is dispatched up the widget hierarchy. } + xpMsg_ButtonStateChanged = 1301 +; + +{___________________________________________________________________________ + * TEXT FIELD + ___________________________________________________________________________} +{ + The text field widget provides an editable text field including mouse + selection and keyboard navigation. The contents of the text field are its + descriptor. (The descriptor changes as the user types.) + + The text field can have a number of types, that effect the visual layout of + the text field. The text field sends messages to itself so you may control + its behavior. + + If you need to filter keystrokes, add a new handler and intercept the key + press message. Since key presses are passed by pointer, you can modify the + keystroke and pass it through to the text field widget. + + WARNING: in X-Plane before 7.10 (including 6.70) null characters could + crash X-Plane. To prevent this, wrap this object with a filter function + (more instructions can be found on the SDK website). +} + + +CONST + xpWidgetClass_TextField = 4; + + { + Text Field Type Values + + These control the look of the text field. + } + { A field for text entry. } + xpTextEntryField = 0 +; + { A transparent text field. The user can type and the text is drawn, but no } + { background is drawn. You can draw your own background by adding a widget } + { handler and prehandling the draw message. } + xpTextTransparent = 3 +; + { A translucent edit field, dark gray. } + xpTextTranslucent = 4 +; + + { + Text Field Properties + } + { This is the character position the selection starts at, zero based. If it } + { is the same as the end insertion point, the insertion point is not a } + { selection. } + xpProperty_EditFieldSelStart = 1400 +; + { This is the character position of the end of the selection. } + xpProperty_EditFieldSelEnd = 1401 +; + { This is the character position a drag was started at if the user is } + { dragging to select text, or -1 if a drag is not in progress. } + xpProperty_EditFieldSelDragStart = 1402 +; + { This is the type of text field to display, from the above list. } + xpProperty_TextFieldType = 1403 +; + { Set this property to 1 to password protect the field. Characters will be } + { drawn as *s even though the descriptor will contain plain-text. } + xpProperty_PasswordMode = 1404 +; + { The max number of characters you can enter, if limited. Zero means } + { unlimited. } + xpProperty_MaxCharacters = 1405 +; + { The first visible character on the left. This effectively scrolls the text} + { field. } + xpProperty_ScrollPosition = 1406 +; + { The font to draw the field's text with. (An XPLMFontID.) } + xpProperty_Font = 1407 +; + { This is the active side of the insert selection. (Internal) } + xpProperty_ActiveEditSide = 1408 +; + + { + Text Field Messages + } + { The text field sends this message to itself when its text changes. It sends} + { the message up the call chain; param1 is the text field's widget ID. } + xpMsg_TextFieldChanged = 1400 +; + +{___________________________________________________________________________ + * SCROLL BAR + ___________________________________________________________________________} +{ + A standard scroll bar or slider control. The scroll bar has a minimum, + maximum and current value that is updated when the user drags it. The + scroll bar sends continuous messages as it is dragged. +} + + +CONST + xpWidgetClass_ScrollBar = 5; + + { + Scroll Bar Type Values + + This defines how the scroll bar looks. + } + { A standard X-Plane scroll bar (with arrows on the ends). } + xpScrollBarTypeScrollBar = 0 +; + { A slider, no arrows. } + xpScrollBarTypeSlider = 1 +; + + { + Scroll Bar Properties + } + { The current position of the thumb (in between the min and max, inclusive) } + xpProperty_ScrollBarSliderPosition = 1500 +; + { The value the scroll bar has when the thumb is in the lowest position. } + xpProperty_ScrollBarMin = 1501 +; + { The value the scroll bar has when the thumb is in the highest position. } + xpProperty_ScrollBarMax = 1502 +; + { How many units to move the scroll bar when clicking next to the thumb. The } + { scroll bar always moves one unit when the arrows are clicked. } + xpProperty_ScrollBarPageAmount = 1503 +; + { The type of scrollbar from the enums above. } + xpProperty_ScrollBarType = 1504 +; + { Used internally. } + xpProperty_ScrollBarSlop = 1505 +; + + { + Scroll Bar Messages + } + { The scroll bar sends this message when the slider position changes. It } + { sends the message up the call chain; param1 is the Scroll Bar widget ID. } + xpMsg_ScrollBarSliderPositionChanged = 1500 +; + +{___________________________________________________________________________ + * CAPTION + ___________________________________________________________________________} +{ + A caption is a simple widget that shows its descriptor as a string, useful + for labeling parts of a window. It always shows its descriptor as its + string and is otherwise transparent. +} + + +CONST + xpWidgetClass_Caption = 6; + + { + Caption Properties + } + { This property specifies whether the caption is lit; use lit captions } + { against screens. } + xpProperty_CaptionLit = 1600 +; + +{___________________________________________________________________________ + * GENERAL GRAPHICS + ___________________________________________________________________________} +{ + The general graphics widget can show one of many icons available from + X-Plane. +} + + +CONST + xpWidgetClass_GeneralGraphics = 7; + + { + General Graphics Types Values + + These define the icon for the general graphics. + } + xpShip = 4 +; + xpILSGlideScope = 5 +; + xpMarkerLeft = 6 +; + xp_Airport = 7 +; + xpNDB = 8 +; + xpVOR = 9 +; + xpRadioTower = 10 +; + xpAircraftCarrier = 11 +; + xpFire = 12 +; + xpMarkerRight = 13 +; + xpCustomObject = 14 +; + xpCoolingTower = 15 +; + xpSmokeStack = 16 +; + xpBuilding = 17 +; + xpPowerLine = 18 +; + xpVORWithCompassRose = 19 +; + xpOilPlatform = 21 +; + xpOilPlatformSmall = 22 +; + xpWayPoint = 23 +; + + { + General Graphics Properties + } + { This property controls the type of icon that is drawn. } + xpProperty_GeneralGraphicsType = 1700 +; + +{___________________________________________________________________________ + * PROGRESS INDICATOR + ___________________________________________________________________________} +{ + This widget implements a progress indicator as seen when X-Plane starts up. +} + +CONST + xpWidgetClass_Progress = 8; + + { + Progress Indicator Properties + } + { This is the current value of the progress indicator. } + xpProperty_ProgressPosition = 1800 +; + { This is the minimum value, equivalent to 0% filled. } + xpProperty_ProgressMin = 1801 +; + { This is the maximum value, equivalent to 100% filled. } + xpProperty_ProgressMax = 1802 +; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPUIGraphics.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPUIGraphics.pas new file mode 100644 index 0000000..65e0636 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPUIGraphics.pas @@ -0,0 +1,342 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPUIGraphics; +INTERFACE + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * UI GRAPHICS + ___________________________________________________________________________} + + { + XPWindowStyle + + There are a few built-in window styles in X-Plane that you can use. + + Note that X-Plane 6 does not offer real shadow-compositing; you must make + sure to put a window on top of another window of the right style to the + shadows work, etc. This applies to elements with insets and shadows. The + rules are: + + Sub windows must go on top of main windows, and screens and list views on + top of subwindows. Only help and main windows can be over the main screen. + + With X-Plane 7 any window or element may be placed over any other element. + + Some windows are scaled by stretching, some by repeating. The drawing + routines know which scaling method to use. The list view cannot be rescaled + in X-Plane 6 because it has both a repeating pattern and a gradient in one + element. All other elements can be rescaled. + } +TYPE + XPWindowStyle = ( + { An LCD screen that shows help. } + xpWindow_Help = 0 + + { A dialog box window. } + ,xpWindow_MainWindow = 1 + + { A panel or frame within a dialog box window. } + ,xpWindow_SubWindow = 2 + + { An LCD screen within a panel to hold text displays. } + ,xpWindow_Screen = 4 + + { A list view within a panel for scrolling file names, etc. } + ,xpWindow_ListView = 5 + + ); + PXPWindowStyle = ^XPWindowStyle; + + { + XPDrawWindow + + This routine draws a window of the given dimensions at the given offset on + the virtual screen in a given style. The window is automatically scaled as + appropriate using a bitmap scaling technique (scaling or repeating) as + appropriate to the style. + } + PROCEDURE XPDrawWindow( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inStyle : XPWindowStyle); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWindowDefaultDimensions + + This routine returns the default dimensions for a window. Output is either + a minimum or fixed value depending on whether the window is scalable. + } + PROCEDURE XPGetWindowDefaultDimensions( + inStyle : XPWindowStyle; + outWidth : PInteger; { Can be nil } + outHeight : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPElementStyle + + Elements are individually drawable UI things like push buttons, etc. The + style defines what kind of element you are drawing. Elements can be + stretched in one or two dimensions (depending on the element). Some + elements can be lit. + + In X-Plane 6 some elements must be drawn over metal. Some are scalable and + some are not. Any element can be drawn anywhere in X-Plane 7. + + Scalable Axis Required Background + } +TYPE + XPElementStyle = ( + { x metal } + xpElement_TextField = 6 + + { none metal } + ,xpElement_CheckBox = 9 + + { none metal } + ,xpElement_CheckBoxLit = 10 + + { none window header } + ,xpElement_WindowCloseBox = 14 + + { none window header } + ,xpElement_WindowCloseBoxPressed = 15 + + { x metal } + ,xpElement_PushButton = 16 + + { x metal } + ,xpElement_PushButtonLit = 17 + + { none any } + ,xpElement_OilPlatform = 24 + + { none any } + ,xpElement_OilPlatformSmall = 25 + + { none any } + ,xpElement_Ship = 26 + + { none any } + ,xpElement_ILSGlideScope = 27 + + { none any } + ,xpElement_MarkerLeft = 28 + + { none any } + ,xpElement_Airport = 29 + + { none any } + ,xpElement_Waypoint = 30 + + { none any } + ,xpElement_NDB = 31 + + { none any } + ,xpElement_VOR = 32 + + { none any } + ,xpElement_RadioTower = 33 + + { none any } + ,xpElement_AircraftCarrier = 34 + + { none any } + ,xpElement_Fire = 35 + + { none any } + ,xpElement_MarkerRight = 36 + + { none any } + ,xpElement_CustomObject = 37 + + { none any } + ,xpElement_CoolingTower = 38 + + { none any } + ,xpElement_SmokeStack = 39 + + { none any } + ,xpElement_Building = 40 + + { none any } + ,xpElement_PowerLine = 41 + + { none metal } + ,xpElement_CopyButtons = 45 + + { none metal } + ,xpElement_CopyButtonsWithEditingGrid = 46 + + { x, y metal } + ,xpElement_EditingGrid = 47 + + { THIS CAN PROBABLY BE REMOVED } + ,xpElement_ScrollBar = 48 + + { none any } + ,xpElement_VORWithCompassRose = 49 + + { none metal } + ,xpElement_Zoomer = 51 + + { x, y metal } + ,xpElement_TextFieldMiddle = 52 + + { none metal } + ,xpElement_LittleDownArrow = 53 + + { none metal } + ,xpElement_LittleUpArrow = 54 + + { none metal } + ,xpElement_WindowDragBar = 61 + + { none metal } + ,xpElement_WindowDragBarSmooth = 62 + + ); + PXPElementStyle = ^XPElementStyle; + + { + XPDrawElement + + XPDrawElement draws a given element at an offset on the virtual screen in + set dimensions. + *Even* if the element is not scalable, it will be scaled if the width and + height do not match the preferred dimensions; it'll just look ugly. Pass + inLit to see the lit version of the element; if the element cannot be lit + this is ignored. + } + PROCEDURE XPDrawElement( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inStyle : XPElementStyle; + inLit : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetElementDefaultDimensions + + This routine returns the recommended or minimum dimensions of a given UI + element. outCanBeLit tells whether the element has both a lit and unlit + state. Pass `NULL` to not receive any of these parameters. + } + PROCEDURE XPGetElementDefaultDimensions( + inStyle : XPElementStyle; + outWidth : PInteger; { Can be nil } + outHeight : PInteger; { Can be nil } + outCanBeLit : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPTrackStyle + + A track is a UI element that displays a value vertically or horizontally. + X-Plane has three kinds of tracks: scroll bars, sliders, and progress bars. + Tracks can be displayed either horizontally or vertically; tracks will + choose their own layout based on the larger dimension of their dimensions + (e.g. they know if they are tall or wide). Sliders may be lit or unlit + (showing the user manipulating them). + + - ScrollBar: this is a standard scroll bar with arrows and a thumb to drag. + - Slider: this is a simple track with a ball in the middle that can be + slid. + - Progress: this is a progress indicator showing how a long task is going. + } +TYPE + XPTrackStyle = ( + { not over metal can be lit can be rotated } + xpTrack_ScrollBar = 0 + + { over metal can be lit can be rotated } + ,xpTrack_Slider = 1 + + { over metal cannot be lit cannot be rotated } + ,xpTrack_Progress = 2 + + ); + PXPTrackStyle = ^XPTrackStyle; + + { + XPDrawTrack + + This routine draws a track. You pass in the track dimensions and size; the + track picks the optimal orientation for these dimensions. Pass in the + track's minimum current and maximum values; the indicator will be + positioned appropriately. You can also specify whether the track is lit or + not. + } + PROCEDURE XPDrawTrack( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inMin : Integer; + inMax : Integer; + inValue : Integer; + inTrackStyle : XPTrackStyle; + inLit : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetTrackDefaultDimensions + + This routine returns a track's default smaller dimension; all tracks are + scalable in the larger dimension. It also returns whether a track can be + lit. + } + PROCEDURE XPGetTrackDefaultDimensions( + inStyle : XPTrackStyle; + outWidth : PInteger; + outCanBeLit : PInteger); + cdecl; external XPWIDGETS.DLL; + + { + XPGetTrackMetrics + + This routine returns the metrics of a track. If you want to write UI code + to manipulate a track, this routine helps you know where the mouse + locations are. For most other elements, the rectangle the element is drawn + in is enough information. However, the scrollbar drawing routine does some + automatic placement; this routine lets you know where things ended up. You + pass almost everything you would pass to the draw routine. You get out the + orientation, and other useful stuff. + + Besides orientation, you get five dimensions for the five parts of a + scrollbar, which are the down button, down area (area before the thumb), + the thumb, and the up area and button. For horizontal scrollers, the left + button decreases; for vertical scrollers, the top button decreases. + } + PROCEDURE XPGetTrackMetrics( + inX1 : Integer; + inY1 : Integer; + inX2 : Integer; + inY2 : Integer; + inMin : Integer; + inMax : Integer; + inValue : Integer; + inTrackStyle : XPTrackStyle; + outIsVertical : PInteger; + outDownBtnSize : PInteger; + outDownPageSize : PInteger; + outThumbSize : PInteger; + outUpPageSize : PInteger; + outUpBtnSize : PInteger); + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgetDefs.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgetDefs.pas new file mode 100644 index 0000000..1cc342f --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgetDefs.pas @@ -0,0 +1,427 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgetDefs; +INTERFACE + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * WIDGET DEFINITIONS + ___________________________________________________________________________} +{ + A widget is a call-back driven screen entity like a push-button, window, + text entry field, etc. + + Use the widget API to create widgets of various classes. You can nest them + into trees of widgets to create complex user interfaces. +} + + +TYPE + { + XPWidgetID + + A Widget ID is an opaque unique non-zero handle identifying your widget. + Use 0 to specify "no widget". This type is defined as wide enough to hold a + pointer. You receive a widget ID when you create a new widget and then use + that widget ID to further refer to the widget. + } + XPWidgetID = pointer; + PXPWidgetID = ^XPWidgetID; + + { + XPWidgetPropertyID + + Properties are values attached to instances of your widgets. A property is + identified by a 32-bit ID and its value is the width of a pointer. + + Each widget instance may have a property or not have it. When you set a + property on a widget for the first time, the property is added to the + widget; it then stays there for the life of the widget. + + Some property IDs are predefined by the widget package; you can make up + your own property IDs as well. + } + XPWidgetPropertyID = ( + { A window's refcon is an opaque value used by client code to find other data} + { based on it. } + xpProperty_Refcon = 0 + + { These properties are used by the utlities to implement dragging. } + ,xpProperty_Dragging = 1 + + ,xpProperty_DragXOff = 2 + + ,xpProperty_DragYOff = 3 + + { Is the widget hilited? (For widgets that support this kind of thing.) } + ,xpProperty_Hilited = 4 + + { Is there a C++ object attached to this widget? } + ,xpProperty_Object = 5 + + { If this property is 1, the widget package will use OpenGL to restrict } + { drawing to the Wiget's exposed rectangle. } + ,xpProperty_Clip = 6 + + { Is this widget enabled (for those that have a disabled state too)? } + ,xpProperty_Enabled = 7 + + { NOTE: Property IDs 1 - 999 are reserved for the widgets library. } + { } + { NOTE: Property IDs 1000 - 9999 are allocated to the standard widget classes} + { provided with the library. } + { } + { Properties 1000 - 1099 are for widget class 0, 1100 - 1199 for widget class} + { 1, etc. } + ,xpProperty_UserStart = 10000 + + ); + PXPWidgetPropertyID = ^XPWidgetPropertyID; + + { + XPMouseState_t + + When the mouse is clicked or dragged, a pointer to this structure is passed + to your widget function. + } + XPMouseState_t = RECORD + x : Integer; + y : Integer; + { Mouse Button number, left = 0 (right button not yet supported. } + button : Integer; +{$IFDEF XPLM200} + { Scroll wheel delta (button in this case would be the wheel axis number). } + delta : Integer; +{$ENDIF XPLM200} + END; + PXPMouseState_t = ^XPMouseState_t; + + { + XPKeyState_t + + When a key is pressed, a pointer to this struct is passed to your widget + function. + } + XPKeyState_t = RECORD + { The ASCII key that was pressed. WARNING: this may be 0 for some non-ASCII } + { key sequences. } + key : XPLMChar; + { The flags. Make sure to check this if you only want key-downs! } + flags : XPLMKeyFlags; + { The virtual key code for the key } + vkey : XPLMChar; + END; + PXPKeyState_t = ^XPKeyState_t; + + { + XPWidgetGeometryChange_t + + This structure contains the deltas for your widget's geometry when it + changes. + } + XPWidgetGeometryChange_t = RECORD + dx : Integer; + { +Y = the widget moved up } + dy : Integer; + dwidth : Integer; + dheight : Integer; + END; + PXPWidgetGeometryChange_t = ^XPWidgetGeometryChange_t; + + { + XPDispatchMode + + The dispatching modes describe how the widgets library sends out messages. + Currently there are three modes: + } + XPDispatchMode = ( + { The message will only be sent to the target widget. } + xpMode_Direct = 0 + + { The message is sent to the target widget, then up the chain of parents } + { until the message is handled or a parentless widget is reached. } + ,xpMode_UpChain = 1 + + { The message is sent to the target widget and then all of its children } + { recursively depth-first. } + ,xpMode_Recursive = 2 + + { The message is snet just to the target, but goes to every callback, even if} + { it is handled. } + ,xpMode_DirectAllCallbacks = 3 + + { The message is only sent to the very first handler even if it is not } + { accepted. (This is really only useful for some internal widget library } + { functions.) } + ,xpMode_Once = 4 + + ); + PXPDispatchMode = ^XPDispatchMode; + + { + XPWidgetClass + + Widget classes define predefined widget types. A widget class basically + specifies from a library the widget function to be used for the widget. + Most widgets can be made right from classes. + } + XPWidgetClass = Integer; + PXPWidgetClass = ^XPWidgetClass; + +CONST + { An unspecified widget class. Other widget classes are in } + { XPStandardWidgets.h } + xpWidgetClass_None = 0; + +{___________________________________________________________________________ + * WIDGET MESSAGES + ___________________________________________________________________________} + + { + XPWidgetMessage + + Widgets receive 32-bit messages indicating what action is to be taken or + notifications of events. The list of messages may be expanded. + } +TYPE + XPWidgetMessage = ( + { No message, should not be sent. } + xpMsg_None = 0 + + { The create message is sent once per widget that is created with your widget} + { function and once for any widget that has your widget function attached. } + { } + { Dispatching: Direct } + { } + { Param 1: 1 if you are being added as a subclass, 0 if the widget is first } + { being created. } + ,xpMsg_Create = 1 + + { The destroy message is sent once for each message that is destroyed that } + { has your widget function. } + { } + { Dispatching: Direct for all } + { } + { Param 1: 1 if being deleted by a recursive delete to the parent, 0 for } + { explicit deletion. } + ,xpMsg_Destroy = 2 + + { The paint message is sent to your widget to draw itself. The paint message } + { is the bare-bones message; in response you must draw yourself, draw your } + { children, set up clipping and culling, check for visibility, etc. If you } + { don't want to do all of this, ignore the paint message and a draw message } + { (see below) will be sent to you. } + { } + { Dispatching: Direct } + ,xpMsg_Paint = 3 + + { The draw message is sent to your widget when it is time to draw yourself. } + { OpenGL will be set up to draw in 2-d global screen coordinates, but you } + { should use the XPLM to set up OpenGL state. } + { } + { Dispatching: Direct } + ,xpMsg_Draw = 4 + + { The key press message is sent once per key that is pressed. The first } + { parameter is the type of key code (integer or char) and the second is the } + { code itself. By handling this event, you consume the key stroke. } + { } + { Handling this message 'consumes' the keystroke; not handling it passes it } + { to your parent widget. } + { } + { Dispatching: Up Chain } + { } + { Param 1: A pointer to an XPKeyState_t structure with the keystroke. } + ,xpMsg_KeyPress = 5 + + { Keyboard focus is being given to you. By handling this message you accept } + { keyboard focus. The first parameter will be one if a child of yours gave up} + { focus to you, 0 if someone set focus on you explicitly. } + { } + { Handling this message accepts focus; not handling refuses focus. } + { } + { Dispatching: direct } + { } + { Param 1: 1 if you are gaining focus because your child is giving it up, 0 } + { if someone is explicitly giving you focus. } + ,xpMsg_KeyTakeFocus = 6 + + { Keyboard focus is being taken away from you. The first parameter will be } + { one if you are losing focus because another widget is taking it, or 0 if } + { someone called the API to make you lose focus explicitly. } + { } + { Dispatching: Direct } + { } + { Param 1: 1 if focus is being taken by another widget, 0 if code requested } + { to remove focus. } + ,xpMsg_KeyLoseFocus = 7 + + { You receive one mousedown event per click with a mouse-state structure } + { pointed to by parameter 1, by accepting this you eat the click, otherwise } + { your parent gets it. You will not receive drag and mouse up messages if you} + { do not accept the down message. } + { } + { Handling this message consumes the mouse click, not handling it passes it } + { to the next widget. You can act 'transparent' as a window by never handling} + { moues clicks to certain areas. } + { } + { Dispatching: Up chain NOTE: Technically this is direct dispatched, but the } + { widgets library will shop it to each widget until one consumes the click, } + { making it effectively "up chain". } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseDown = 8 + + { You receive a series of mouse drag messages (typically one per frame in the} + { sim) as the mouse is moved once you have accepted a mouse down message. } + { Parameter one points to a mouse-state structure describing the mouse } + { location. You will continue to receive these until the mouse button is } + { released. You may receive multiple mouse state messages with the same mouse} + { position. You will receive mouse drag events even if the mouse is dragged } + { out of your current or original bounds at the time of the mouse down. } + { } + { Dispatching: Direct } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseDrag = 9 + + { The mouseup event is sent once when the mouse button is released after a } + { drag or click. You only receive this message if you accept the mouseDown } + { message. Parameter one points to a mouse state structure. } + { } + { Dispatching: Direct } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseUp = 10 + + { Your geometry or a child's geometry is being changed. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the original reshaped target. } + { } + { Param 2: A pointer to a XPWidgetGeometryChange_t struct describing the } + { change. } + ,xpMsg_Reshape = 11 + + { Your exposed area has changed. } + { } + { Dispatching: Direct } + ,xpMsg_ExposedChanged = 12 + + { A child has been added to you. The child's ID is passed in parameter one. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of the child being added. } + ,xpMsg_AcceptChild = 13 + + { A child has been removed from to you. The child's ID is passed in parameter} + { one. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of the child being removed. } + ,xpMsg_LoseChild = 14 + + { You now have a new parent, or have no parent. The parent's ID is passed in,} + { or 0 for no parent. } + { } + { Dispatching: Direct } + { } + { Param 1: The Widget ID of your parent } + ,xpMsg_AcceptParent = 15 + + { You or a child has been shown. Note that this does not include you being } + { shown because your parent was shown, you were put in a new parent, your } + { root was shown, etc. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the shown widget. } + ,xpMsg_Shown = 16 + + { You have been hidden. See limitations above. } + { } + { Dispatching: Up chain } + { } + { Param 1: The widget ID of the hidden widget. } + ,xpMsg_Hidden = 17 + + { Your descriptor has changed. } + { } + { Dispatching: Direct } + ,xpMsg_DescriptorChanged = 18 + + { A property has changed. Param 1 contains the property ID. } + { } + { Dispatching: Direct } + { } + { Param 1: The Property ID being changed. } + { } + { Param 2: The new property value } + ,xpMsg_PropertyChanged = 19 + +{$IFDEF XPLM200} + { The mouse wheel has moved. } + { } + { Return 1 to consume the mouse wheel move, or 0 to pass the message to a } + { parent. Dispatching: Up chain } + { } + { Param 1: A pointer to an XPMouseState_t containing the mouse status. } + ,xpMsg_MouseWheel = 20 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { The cursor is over your widget. If you consume this message, change the } + { XPLMCursorStatus value to indicate the desired result, with the same rules } + { as in XPLMDisplay.h. } + { } + { Return 1 to consume this message, 0 to pass it on. } + { } + { Dispatching: Up chain Param 1: A pointer to an XPMouseState_t struct } + { containing the mouse status. } + { } + { Param 2: A pointer to a XPLMCursorStatus - set this to the cursor result } + { you desire. } + ,xpMsg_CursorAdjust = 21 +{$ENDIF XPLM200} + + { NOTE: Message IDs 1000 - 9999 are allocated to the standard widget classes } + { provided with the library with 1000 - 1099 for widget class 0, 1100 - 1199 } + { for widget class 1, etc. Message IDs 10,000 and beyond are for plugin use. } + ,xpMsg_UserStart = 10000 + + ); + PXPWidgetMessage = ^XPWidgetMessage; + +{___________________________________________________________________________ + * WIDGET CALLBACK FUNCTION + ___________________________________________________________________________} + + { + XPWidgetFunc_t + + This function defines your custom widget's behavior. It will be called by + the widgets library to send messages to your widget. The message and widget + ID are passed in, as well as two ptr-width signed parameters whose meaning + varies with the message. Return 1 to indicate that you have processed the + message, 0 to indicate that you have not. For any message that is not + understood, return 0. + } +TYPE + XPWidgetFunc_t = FUNCTION( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; cdecl; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgetUtils.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgetUtils.pas new file mode 100644 index 0000000..9621126 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgetUtils.pas @@ -0,0 +1,197 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgetUtils; +INTERFACE +{ + ## USAGE NOTES + + The XPWidgetUtils library contains useful functions that make writing and + using widgets less of a pain. + + One set of functions are the widget behavior functions. These functions + each add specific useful behaviors to widgets. They can be used in two + manners: + + 1. You can add a widget behavior function to a widget as a callback proc + using the XPAddWidgetCallback function. The widget will gain that + behavior. Remember that the last function you add has highest priority. + You can use this to change or augment the behavior of an existing + finished widget. + 2. You can call a widget function from inside your own widget function. + This allows you to include useful behaviors in custom-built widgets. A + number of the standard widgets get their behavior from this library. To + do this, call the behavior function from your function first. If it + returns 1, that means it handled the event and you don't need to; simply + return 1. +} + +USES + XPWidgetDefs; + {$A4} +{___________________________________________________________________________ + * GENERAL UTILITIES + ___________________________________________________________________________} + + + { + XPWidgetCreate_t + + This structure contains all of the parameters needed to create a wiget. It + is used with XPUCreateWidgets to create widgets in bulk from an array. All + parameters correspond to those of XPCreateWidget except for the container + index. + + If the container index is equal to the index of a widget in the array, the + widget in the array passed to XPUCreateWidgets is used as the parent of + this widget. Note that if you pass an index greater than your own position + in the array, the parent you are requesting will not exist yet. + + If the container index is NO_PARENT, the parent widget is specified as + NULL. If the container index is PARAM_PARENT, the widget passed into + XPUCreateWidgets is used. + } +TYPE + XPWidgetCreate_t = RECORD + left : Integer; + top : Integer; + right : Integer; + bottom : Integer; + visible : Integer; + descriptor : XPLMString; + { Whether ethis widget is a root wiget } + isRoot : Integer; + { The index of the widget to contain within, or a constant } + containerIndex : Integer; + widgetClass : XPWidgetClass; + END; + PXPWidgetCreate_t = ^XPWidgetCreate_t; + +CONST + NO_PARENT = -1; + + PARAM_PARENT = -2; + + + { + XPUCreateWidgets + + This function creates a series of widgets from a table (see + XPCreateWidget_t above). Pass in an array of widget creation structures and + an array of widget IDs that will receive each widget. + + Widget parents are specified by index into the created widget table, + allowing you to create nested widget structures. You can create multiple + widget trees in one table. Generally you should create widget trees from + the top down. + + You can also pass in a widget ID that will be used when the widget's parent + is listed as PARAM_PARENT; this allows you to embed widgets created with + XPUCreateWidgets in a widget created previously. + } + PROCEDURE XPUCreateWidgets( + inWidgetDefs : PXPWidgetCreate_t; + inCount : Integer; + inParamParent : XPWidgetID; + ioWidgets : PXPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPUMoveWidgetBy + + Simply moves a widget by an amount, +x = right, +y=up, without resizing the + widget. + } + PROCEDURE XPUMoveWidgetBy( + inWidget : XPWidgetID; + inDeltaX : Integer; + inDeltaY : Integer); + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * LAYOUT MANAGERS + ___________________________________________________________________________} +{ + The layout managers are widget behavior functions for handling where + widgets move. Layout managers can be called from a widget function or + attached to a widget later. +} + + + { + XPUFixedLayout + + This function causes the widget to maintain its children in fixed position + relative to itself as it is resized. Use this on the top level 'window' + widget for your window. + } + FUNCTION XPUFixedLayout( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * WIDGET PROC BEHAVIORS + ___________________________________________________________________________} +{ + These widget behavior functions add other useful behaviors to widgets. + These functions cannot be attached to a widget; they must be called from + your widget function. +} + + + { + XPUSelectIfNeeded + + This causes the widget to bring its window to the foreground if it is not + already. inEatClick specifies whether clicks in the background should be + consumed by bringin the window to the foreground. + } + FUNCTION XPUSelectIfNeeded( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inEatClick : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPUDefocusKeyboard + + This causes a click in the widget to send keyboard focus back to X-Plane. + This stops editing of any text fields, etc. + } + FUNCTION XPUDefocusKeyboard( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inEatClick : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPUDragWidget + + XPUDragWidget drags the widget in response to mouse clicks. Pass in not + only the event, but the global coordinates of the drag region, which might + be a sub-region of your widget (for example, a title bar). + } + FUNCTION XPUDragWidget( + inMessage : XPWidgetMessage; + inWidget : XPWidgetID; + inParam1 : intptr_t; + inParam2 : intptr_t; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgets.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgets.pas new file mode 100644 index 0000000..46ae542 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/Widgets/XPWidgets.pas @@ -0,0 +1,527 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPWidgets; +INTERFACE +{ + ## THEORY OF OPERATION AND NOTES + + Widgets are persistent view 'objects' for X-Plane. A widget is an object + referenced by its opaque handle (widget ID) and the APIs in this file. You + cannot access the widget's guts directly. Every Widget has the following + intrinsic data: + + - A bounding box defined in global screen coordinates with 0,0 in the + bottom left and +y = up, +x = right. + - A visible box, which is the intersection of the bounding box with the + widget's parents visible box. + - Zero or one parent widgets. (Always zero if the widget is a root widget. + - Zero or more child widgets. + - Whether the widget is a root. Root widgets are the top level plugin + windows. + - Whether the widget is visible. + - A text string descriptor, whose meaning varies from widget to widget. + - An arbitrary set of 32 bit integral properties defined by 32-bit integral + keys. This is how specific widgets store specific data. + - A list of widget callbacks proc that implements the widgets behaviors. + + The Widgets library sends messages to widgets to request specific behaviors + or notify the widget of things. + + Widgets may have more than one callback function, in which case messages + are sent to the most recently added callback function until the message is + handled. Messages may also be sent to parents or children; see the + XPWidgetDefs.h header file for the different widget message dispatching + functions. By adding a callback function to a window you can 'subclass' its + behavior. + + A set of standard widgets are provided that serve common UI purposes. You + can also customize or implement entirely custom widgets. + + Widgets are different than other view hierarchies (most notably Win32, + which they bear a striking resemblance to) in the following ways: + + - Not all behavior can be patched. State that is managed by the XPWidgets + DLL and not by individual widgets cannot be customized. + - All coordinates are in global screen coordinates. Coordinates are not + relative to an enclosing widget, nor are they relative to a display + window. + - Widget messages are always dispatched synchronously, and there is no + concept of scheduling an update or a dirty region. Messages originate + from X-Plane as the sim cycle goes by. Since X-Plane is constantly + redrawing, so are widgets; there is no need to mark a part of a widget as + 'needing redrawing' because redrawing happens frequently whether the + widget needs it or not. + - Any widget may be a 'root' widget, causing it to be drawn; there is no + relationship between widget class and rootness. Root widgets are + imlemented as XPLMDisply windows. +} + +USES + XPWidgetDefs, XPLMDisplay; + {$A4} +{___________________________________________________________________________ + * WIDGET CREATION AND MANAGEMENT + ___________________________________________________________________________} + + { + XPCreateWidget + + This function creates a new widget and returns the new widget's ID to you. + If the widget creation fails for some reason, it returns NULL. Widget + creation will fail either if you pass a bad class ID or if there is not + adequate memory. + + Input Parameters: + + - Top, left, bottom, and right in global screen coordinates defining the + widget's location on the screen. + - inVisible is 1 if the widget should be drawn, 0 to start the widget as + hidden. + - inDescriptor is a null terminated string that will become the widget's + descriptor. + - inIsRoot is 1 if this is going to be a root widget, 0 if it will not be. + - inContainer is the ID of this widget's container. It must be 0 for a root + widget. for a non-root widget, pass the widget ID of the widget to place + this widget within. If this widget is not going to start inside another + widget, pass 0; this new widget will then just be floating off in space + (and will not be drawn until it is placed in a widget. + - inClass is the class of the widget to draw. Use one of the predefined + class-IDs to create a standard widget. + + A note on widget embedding: a widget is only called (and will be drawn, + etc.) if it is placed within a widget that will be called. Root widgets are + always called. So it is possible to have whole chains of widgets that are + simply not called. You can preconstruct widget trees and then place them + into root widgets later to activate them if you wish. + } + FUNCTION XPCreateWidget( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inVisible : Integer; + inDescriptor : XPLMString; + inIsRoot : Integer; + inContainer : XPWidgetID; + inClass : XPWidgetClass) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPCreateCustomWidget + + This function is the same as XPCreateWidget except that instead of passing + a class ID, you pass your widget callback function pointer defining the + widget. Use this function to define a custom widget. All parameters are the + same as XPCreateWidget, except that the widget class has been replaced with + the widget function. + } + FUNCTION XPCreateCustomWidget( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inVisible : Integer; + inDescriptor : XPLMString; + inIsRoot : Integer; + inContainer : XPWidgetID; + inCallback : XPWidgetFunc_t) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPDestroyWidget + + This class destroys a widget. Pass in the ID of the widget to kill. If you + pass 1 for inDestroyChilren, the widget's children will be destroyed first, + then this widget will be destroyed. (Furthermore, the widget's children + will be destroyed with the inDestroyChildren flag set to 1, so the + destruction will recurse down the widget tree.) If you pass 0 for this + flag, the child widgets will simply end up with their parent set to 0. + } + PROCEDURE XPDestroyWidget( + inWidget : XPWidgetID; + inDestroyChildren : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPSendMessageToWidget + + This sends any message to a widget. You should probably not go around + simulating the predefined messages that the widgets library defines for + you. You may however define custom messages for your widgets and send them + with this method. + + This method supports several dispatching patterns; see XPDispatchMode for + more info. The function returns 1 if the message was handled, 0 if it was + not. + + For each widget that receives the message (see the dispatching modes), each + widget function from the most recently installed to the oldest one receives + the message in order until it is handled. + } + FUNCTION XPSendMessageToWidget( + inWidget : XPWidgetID; + inMessage : XPWidgetMessage; + inMode : XPDispatchMode; + inParam1 : intptr_t; + inParam2 : intptr_t) : Integer; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * WIDGET POSITIONING AND VISIBILITY + ___________________________________________________________________________} + + { + XPPlaceWidgetWithin + + This function changes which container a widget resides in. You may NOT use + this function on a root widget! inSubWidget is the widget that will be + moved. Pass a widget ID in inContainer to make inSubWidget be a child of + inContainer. It will become the last/closest widget in the container. Pass + 0 to remove the widget from any container. Any call to this other than + passing the widget ID of the old parent of the affected widget will cause + the widget to be removed from its old parent. Placing a widget within its + own parent simply makes it the last widget. + + NOTE: this routine does not reposition the sub widget in global + coordinates. If the container has layout management code, it will + reposition the subwidget for you, otherwise you must do it with + SetWidgetGeometry. + } + PROCEDURE XPPlaceWidgetWithin( + inSubWidget : XPWidgetID; + inContainer : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPCountChildWidgets + + This routine returns the number of widgets another widget contains. + } + FUNCTION XPCountChildWidgets( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetNthChildWidget + + This routine returns the widget ID of a child widget by index. Indexes are + 0 based, from 0 to one minus the number of widgets in the parent, + inclusive. If the index is invalid, 0 is returned. + } + FUNCTION XPGetNthChildWidget( + inWidget : XPWidgetID; + inIndex : Integer) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPGetParentWidget + + Returns the parent of a widget, or 0 if the widget has no parent. Root + widgets never have parents and therefore always return 0. + } + FUNCTION XPGetParentWidget( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPShowWidget + + This routine makes a widget visible if it is not already. Note that if a + widget is not in a rooted widget hierarchy or one of its parents is not + visible, it will still not be visible to the user. + } + PROCEDURE XPShowWidget( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPHideWidget + + Makes a widget invisible. See XPShowWidget for considerations of when a + widget might not be visible despite its own visibility state. + } + PROCEDURE XPHideWidget( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPIsWidgetVisible + + This returns 1 if a widget is visible, 0 if it is not. Note that this + routine takes into consideration whether a parent is invisible. Use this + routine to tell if the user can see the widget. + } + FUNCTION XPIsWidgetVisible( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPFindRootWidget + + Returns the Widget ID of the root widget that contains the passed in widget + or NULL if the passed in widget is not in a rooted hierarchy. + } + FUNCTION XPFindRootWidget( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPBringRootWidgetToFront + + This routine makes the specified widget be in the front most widget + hierarchy. If this widget is a root widget, its widget hierarchy comes to + front, otherwise the widget's root is brought to the front. If this widget + is not in an active widget hiearchy (e.g. there is no root widget at the + top of the tree), this routine does nothing. + } + PROCEDURE XPBringRootWidgetToFront( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPIsWidgetInFront + + This routine returns true if this widget's hierarchy is the front most + hierarchy. It returns false if the widget's hierarchy is not in front, or + if the widget is not in a rooted hierarchy. + } + FUNCTION XPIsWidgetInFront( + inWidget : XPWidgetID) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetGeometry + + This routine returns the bounding box of a widget in global coordinates. + Pass NULL for any parameter you are not interested in. + } + PROCEDURE XPGetWidgetGeometry( + inWidget : XPWidgetID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + + { + XPSetWidgetGeometry + + This function changes the bounding box of a widget. + } + PROCEDURE XPSetWidgetGeometry( + inWidget : XPWidgetID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetForLocation + + Given a widget and a location, this routine returns the widget ID of the + child of that widget that owns that location. If inRecursive is true then + this will return a child of a child of a widget as it tries to find the + deepest widget at that location. If inVisibleOnly is true, then only + visible widgets are considered, otherwise all widgets are considered. The + widget ID passed for inContainer will be returned if the location is in + that widget but not in a child widget. 0 is returned if the location is not + in the container. + + NOTE: if a widget's geometry extends outside its parents geometry, it will + not be returned by this call for mouse locations outside the parent + geometry. The parent geometry limits the child's eligibility for mouse + location. + } + FUNCTION XPGetWidgetForLocation( + inContainer : XPWidgetID; + inXOffset : Integer; + inYOffset : Integer; + inRecursive : Integer; + inVisibleOnly : Integer) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetExposedGeometry + + This routine returns the bounds of the area of a widget that is completely + within its parent widgets. Since a widget's bounding box can be outside its + parent, part of its area will not be elligible for mouse clicks and should + not draw. Use XPGetWidgetGeometry to find out what area defines your + widget's shape, but use this routine to find out what area to actually draw + into. Note that the widget library does not use OpenGL clipping to keep + frame rates up, although you could use it internally. + } + PROCEDURE XPGetWidgetExposedGeometry( + inWidgetID : XPWidgetID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * ACCESSING WIDGET DATA + ___________________________________________________________________________} + + { + XPSetWidgetDescriptor + + Every widget has a descriptor, which is a text string. What the text string + is used for varies from widget to widget; for example, a push button's text + is its descriptor, a caption shows its descriptor, and a text field's + descriptor is the text being edited. In other words, the usage for the text + varies from widget to widget, but this API provides a universal and + convenient way to get at it. While not all UI widgets need their + descriptor, many do. + } + PROCEDURE XPSetWidgetDescriptor( + inWidget : XPWidgetID; + inDescriptor : XPLMString); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetDescriptor + + This routine returns the widget's descriptor. Pass in the length of the + buffer you are going to receive the descriptor in. The descriptor will be + null terminated for you. This routine returns the length of the actual + descriptor; if you pass NULL for outDescriptor, you can get the + descriptor's length without getting its text. If the length of the + descriptor exceeds your buffer length, the buffer will not be null + terminated (this routine has 'strncpy' semantics). + } + FUNCTION XPGetWidgetDescriptor( + inWidget : XPWidgetID; + outDescriptor : XPLMString; + inMaxDescLength : Integer) : Integer; + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetUnderlyingWindow + + Returns the window (from the XPLMDisplay API) that backs your widget + window. If you have opted in to modern windows, via a call to + XPLMEnableFeature("XPLM_USE_NATIVE_WIDGET_WINDOWS", 1), you can use the + returned window ID for display APIs like XPLMSetWindowPositioningMode(), + allowing you to pop the widget window out into a real OS window, or move it + into VR. + } + FUNCTION XPGetWidgetUnderlyingWindow( + inWidget : XPWidgetID) : XPLMWindowID; + cdecl; external XPWIDGETS.DLL; + + { + XPSetWidgetProperty + + This function sets a widget's property. Properties are arbitrary values + associated by a widget by ID. + } + PROCEDURE XPSetWidgetProperty( + inWidget : XPWidgetID; + inProperty : XPWidgetPropertyID; + inValue : intptr_t); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetProperty + + This routine returns the value of a widget's property, or 0 if the property + is not defined. If you need to know whether the property is defined, pass a + pointer to an int for inExists; the existence of that property will be + returned in the int. Pass NULL for inExists if you do not need this + information. + } + FUNCTION XPGetWidgetProperty( + inWidget : XPWidgetID; + inProperty : XPWidgetPropertyID; + inExists : PInteger) : intptr_t; { Can be nil } + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * KEYBOARD MANAGEMENT + ___________________________________________________________________________} + + { + XPSetKeyboardFocus + + Controls which widget will receive keystrokes. Pass the widget ID of the + widget to get the keys. Note that if the widget does not care about + keystrokes, they will go to the parent widget, and if no widget cares about + them, they go to X-Plane. + + If you set the keyboard focus to widget ID 0, X-Plane gets keyboard focus. + + This routine returns the widget ID that ended up with keyboard focus, or 0 + for X-Plane. + + Keyboard focus is not changed if the new widget will not accept it. For + setting to X-Plane, keyboard focus is always accepted. + } + FUNCTION XPSetKeyboardFocus( + inWidget : XPWidgetID) : XPWidgetID; + cdecl; external XPWIDGETS.DLL; + + { + XPLoseKeyboardFocus + + This causes the specified widget to lose focus; focus is passed to its + parent, or the next parent that will accept it. This routine does nothing + if this widget does not have focus. + } + PROCEDURE XPLoseKeyboardFocus( + inWidget : XPWidgetID); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetWithFocus + + This routine returns the widget that has keyboard focus, or 0 if X-Plane + has keyboard focus or some other plugin window that does not have widgets + has focus. + } + FUNCTION XPGetWidgetWithFocus: XPWidgetID; + cdecl; external XPWIDGETS.DLL; + +{___________________________________________________________________________ + * CREATING CUSTOM WIDGETS + ___________________________________________________________________________} + + { + XPAddWidgetCallback + + This function adds a new widget callback to a widget. This widget callback + supercedes any existing ones and will receive messages first; if it does + not handle messages they will go on to be handled by pre-existing widgets. + + The widget function will remain on the widget for the life of the widget. + The creation message will be sent to the new callback immediately with the + widget ID, and the destruction message will be sent before the other widget + function receives a destruction message. + + This provides a way to 'subclass' an existing widget. By providing a second + hook that only handles certain widget messages, you can customize or extend + widget behavior. + } + PROCEDURE XPAddWidgetCallback( + inWidget : XPWidgetID; + inNewCallback : XPWidgetFunc_t); + cdecl; external XPWIDGETS.DLL; + + { + XPGetWidgetClassFunc + + Given a widget class, this function returns the callbacks that power that + widget class. + } + FUNCTION XPGetWidgetClassFunc( + inWidgetClass : XPWidgetClass) : XPWidgetFunc_t; + cdecl; external XPWIDGETS.DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMCamera.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMCamera.pas new file mode 100644 index 0000000..ad76fa4 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMCamera.pas @@ -0,0 +1,155 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMCamera; +INTERFACE +{ + The XPLMCamera APIs allow plug-ins to control the camera angle in X-Plane. + This has a number of applications, including but not limited to: + + - Creating new views (including dynamic/user-controllable views) for the + user. + - Creating applications that use X-Plane as a renderer of scenery, + aircrafts, or both. + + The camera is controlled via six parameters: a location in OpenGL + coordinates and pitch, roll and yaw, similar to an airplane's position. + OpenGL coordinate info is described in detail in the XPLMGraphics + documentation; generally you should use the XPLMGraphics routines to + convert from world to local coordinates. The camera's orientation starts + facing level with the ground directly up the negative-Z axis (approximately + north) with the horizon horizontal. It is then rotated clockwise for yaw, + pitched up for positive pitch, and rolled clockwise around the vector it is + looking along for roll. + + You control the camera either either until the user selects a new view or + permanently (the later being similar to how UDP camera control works). You + control the camera by registering a callback per frame from which you + calculate the new camera positions. This guarantees smooth camera motion. + + Use the XPLMDataAccess APIs to get information like the position of the + aircraft, etc. for complex camera positioning. + + Note: if your goal is to move the virtual pilot in the cockpit, this API is + not needed; simply update the datarefs for the pilot's head position. + + For custom exterior cameras, set the camera's mode to an external view + first to get correct sound and 2-d panel behavior. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * CAMERA CONTROL + ___________________________________________________________________________} + + { + XPLMCameraControlDuration + + This enumeration states how long you want to retain control of the camera. + You can retain it indefinitely or until the user selects a new view. + } +TYPE + XPLMCameraControlDuration = ( + { Control the camera until the user picks a new view. } + xplm_ControlCameraUntilViewChanges = 1 + + { Control the camera until your plugin is disabled or another plugin forcably} + { takes control. } + ,xplm_ControlCameraForever = 2 + + ); + PXPLMCameraControlDuration = ^XPLMCameraControlDuration; + + { + XPLMCameraPosition_t + + This structure contains a full specification of the camera. X, Y, and Z are + the camera's position in OpenGL coordiantes; pitch, roll, and yaw are + rotations from a camera facing flat north in degrees. Positive pitch means + nose up, positive roll means roll right, and positive yaw means yaw right, + all in degrees. Zoom is a zoom factor, with 1.0 meaning normal zoom and 2.0 + magnifying by 2x (objects appear larger). + } + XPLMCameraPosition_t = RECORD + x : Single; + y : Single; + z : Single; + pitch : Single; + heading : Single; + roll : Single; + zoom : Single; + END; + PXPLMCameraPosition_t = ^XPLMCameraPosition_t; + + { + XPLMCameraControl_f + + You use an XPLMCameraControl function to provide continuous control over + the camera. You are passed in a structure in which to put the new camera + position; modify it and return 1 to reposition the camera. Return 0 to + surrender control of the camera; camera control will be handled by X-Plane + on this draw loop. The contents of the structure as you are called are + undefined. + + If X-Plane is taking camera control away from you, this function will be + called with inIsLosingControl set to 1 and ioCameraPosition NULL. + } + XPLMCameraControl_f = FUNCTION( + outCameraPosition : PXPLMCameraPosition_t; { Can be nil } + inIsLosingControl : Integer; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMControlCamera + + This function repositions the camera on the next drawing cycle. You must + pass a non-null control function. Specify in inHowLong how long you'd like + control (indefinitely or until a new view mode is set by the user). + } + PROCEDURE XPLMControlCamera( + inHowLong : XPLMCameraControlDuration; + inControlFunc : XPLMCameraControl_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMDontControlCamera + + This function stops you from controlling the camera. If you have a camera + control function, it will not be called with an inIsLosingControl flag. + X-Plane will control the camera on the next cycle. + + For maximum compatibility you should not use this routine unless you are in + posession of the camera. + } + PROCEDURE XPLMDontControlCamera; + cdecl; external XPLM_DLL; + + { + XPLMIsCameraBeingControlled + + This routine returns 1 if the camera is being controlled, zero if it is + not. If it is and you pass in a pointer to a camera control duration, the + current control duration will be returned. + } + FUNCTION XPLMIsCameraBeingControlled( + outCameraControlDuration: PXPLMCameraControlDuration) : Integer; { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMReadCameraPosition + + This function reads the current camera position. + } + PROCEDURE XPLMReadCameraPosition( + outCameraPosition : PXPLMCameraPosition_t); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDataAccess.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDataAccess.pas new file mode 100644 index 0000000..1ad210e --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDataAccess.pas @@ -0,0 +1,690 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDataAccess; +INTERFACE +{ + The data access API gives you a generic, flexible, high performance way to + read and write data to and from X-Plane and other plug-ins. For example, + this API allows you to read and set the nav radios, get the plane location, + determine the current effective graphics frame rate, etc. + + The data access APIs are the way that you read and write data from the sim + as well as other plugins. + + The API works using opaque data references. A data reference is a source of + data; you do not know where it comes from, but once you have it you can + read the data quickly and possibly write it. + + Dataref Lookup + -------------- + + Data references are identified by verbose, permanent string names; by + convention these names use path separates to form a hierarchy of datarefs, + e.g. (sim/cockpit/radios/nav1_freq_hz). The actual opaque numeric value of + the data reference, as returned by the XPLM API, is implementation defined + and changes each time X-Plane is launched; therefore you need to look up + the dataref by path every time your plugin runs. + + The task of looking up a data reference is relatively expensive; look up + your data references once based on the verbose path strings, and save the + opaque data reference value for the duration of your plugin's operation. + Reading and writing data references is relatively fast (the cost is + equivalent to two function calls through function pointers). + + X-Plane publishes over 4000 datarefs; a complete list may be found in the + reference section of the SDK online documentation (from the SDK home page, + choose Documentation). + + Dataref Types + ------------- + + A note on typing: you must know the correct data type to read and write. + APIs are provided for reading and writing data in a number of ways. You can + also double check the data type for a data ref. Automatic type conversion + is not done for you. + + Dataref types are a set, e.g. a dataref can be more than one type. When + this happens, you can choose which API you want to use to read. For + example, it is not uncommon for a dataref to be of type float and double. + This means you can use either XPLMGetDatad or XPLMGetDataf to read it. + + Creating New Datarefs + --------------------- + + X-Plane provides datarefs that come with the sim, but plugins can also + create their own datarefs. A plugin creates a dataref by registering + function callbacks to read and write the dataref. The XPLM will call your + plugin each time some other plugin (or X-Plane) tries to read or write the + dataref. You must provide a read (and optional write) callback for each + data type you support. + + A note for plugins sharing data with other plugins: the load order of + plugins is not guaranteed. To make sure that every plugin publishing data + has published their data references before other plugins try to subscribe, + publish your data references in your start routine but resolve them the + first time your 'enable' routine is called, or the first time they are + needed in code. + + When a plugin that created a dataref is unloaded, it becomes "orphaned". + The dataref handle continues to be usable, but the dataref is not writable, + and reading it will always return 0 (or 0 items for arrays). If the plugin + is reloaded and re-registers the dataref, the handle becomes un-orphaned + and works again. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * READING AND WRITING DATA + ___________________________________________________________________________} +{ + These routines allow you to access data from within X-Plane and sometimes + modify it. +} + + +TYPE + { + XPLMDataRef + + A data ref is an opaque handle to data provided by the simulator or another + plugin. It uniquely identifies one variable (or array of variables) over + the lifetime of your plugin. You never hard code these values; you always + get them from XPLMFindDataRef. + } + XPLMDataRef = pointer; + PXPLMDataRef = ^XPLMDataRef; + + { + XPLMDataTypeID + + This is an enumeration that defines the type of the data behind a data + reference. This allows you to sanity check that the data type matches what + you expect. But for the most part, you will know the type of data you are + expecting from the online documentation. + + Data types each take a bit field; it is legal to have a single dataref be + more than one type of data. Whe this happens, you can pick any matching + get/set API. + } + XPLMDataTypeID = ( + { Data of a type the current XPLM doesn't do. } + xplmType_Unknown = 0 + + { A single 4-byte integer, native endian. } + ,xplmType_Int = 1 + + { A single 4-byte float, native endian. } + ,xplmType_Float = 2 + + { A single 8-byte double, native endian. } + ,xplmType_Double = 4 + + { An array of 4-byte floats, native endian. } + ,xplmType_FloatArray = 8 + + { An array of 4-byte integers, native endian. } + ,xplmType_IntArray = 16 + + { A variable block of data. } + ,xplmType_Data = 32 + + ); + PXPLMDataTypeID = ^XPLMDataTypeID; + + { + XPLMFindDataRef + + Given a c-style string that names the data ref, this routine looks up the + actual opaque XPLMDataRef that you use to read and write the data. The + string names for datarefs are published on the X-Plane SDK web site. + + This function returns NULL if the data ref cannot be found. + + NOTE: this function is relatively expensive; save the XPLMDataRef this + function returns for future use. Do not look up your data ref by string + every time you need to read or write it. + } + FUNCTION XPLMFindDataRef( + inDataRefName : XPLMString) : XPLMDataRef; + cdecl; external XPLM_DLL; + + { + XPLMCanWriteDataRef + + Given a data ref, this routine returns true if you can successfully set the + data, false otherwise. Some datarefs are read-only. + + NOTE: even if a dataref is marked writable, it may not act writable. This + can happen for datarefs that X-Plane writes to on every frame of + simulation. In some cases, the dataref is writable but you have to set a + separate "override" dataref to 1 to stop X-Plane from writing it. + } + FUNCTION XPLMCanWriteDataRef( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMIsDataRefGood + + This function returns true if the passed in handle is a valid dataref that + is not orphaned. + + Note: there is normally no need to call this function; datarefs returned by + XPLMFindDataRef remain valid (but possibly orphaned) unless there is a + complete plugin reload (in which case your plugin is reloaded anyway). + Orphaned datarefs can be safely read and return 0. Therefore you never need + to call XPLMIsDataRefGood to 'check' the safety of a dataref. + (XPLMIsDatarefGood performs some slow checking of the handle validity, so + it has a perormance cost.) + } + FUNCTION XPLMIsDataRefGood( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDataRefTypes + + This routine returns the types of the data ref for accessor use. If a data + ref is available in multiple data types, the bit-wise OR of these types + will be returned. + } + FUNCTION XPLMGetDataRefTypes( + inDataRef : XPLMDataRef) : XPLMDataTypeID; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * DATA ACCESSORS + ___________________________________________________________________________} +{ + These routines read and write the data references. For each supported data + type there is a reader and a writer. + + If the data ref is orphaned or the plugin that provides it is disabled or + there is a type mismatch, the functions that read data will return 0 as a + default value or not modify the passed in memory. The plugins that write + data will not write under these circumstances or if the data ref is + read-only. + + NOTE: to keep the overhead of reading datarefs low, these routines do not + do full validation of a dataref; passing a junk value for a dataref can + result in crashing the sim. The get/set APIs do check for NULL. + + For array-style datarefs, you specify the number of items to read/write and + the offset into the array; the actual number of items read or written is + returned. This may be less to prevent an array-out-of-bounds error. +} + + + { + XPLMGetDatai + + Read an integer data ref and return its value. The return value is the + dataref value or 0 if the dataref is NULL or the plugin is disabled. + } + FUNCTION XPLMGetDatai( + inDataRef : XPLMDataRef) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatai + + Write a new value to an integer data ref. This routine is a no-op if the + plugin publishing the dataref is disabled, the dataref is NULL, or the + dataref is not writable. + } + PROCEDURE XPLMSetDatai( + inDataRef : XPLMDataRef; + inValue : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDataf + + Read a single precision floating point dataref and return its value. The + return value is the dataref value or 0.0 if the dataref is NULL or the + plugin is disabled. + } + FUNCTION XPLMGetDataf( + inDataRef : XPLMDataRef) : Single; + cdecl; external XPLM_DLL; + + { + XPLMSetDataf + + Write a new value to a single precision floating point data ref. This + routine is a no-op if the plugin publishing the dataref is disabled, the + dataref is NULL, or the dataref is not writable. + } + PROCEDURE XPLMSetDataf( + inDataRef : XPLMDataRef; + inValue : Single); + cdecl; external XPLM_DLL; + + { + XPLMGetDatad + + Read a double precision floating point dataref and return its value. The + return value is the dataref value or 0.0 if the dataref is NULL or the + plugin is disabled. + } + FUNCTION XPLMGetDatad( + inDataRef : XPLMDataRef) : Real; + cdecl; external XPLM_DLL; + + { + XPLMSetDatad + + Write a new value to a double precision floating point data ref. This + routine is a no-op if the plugin publishing the dataref is disabled, the + dataref is NULL, or the dataref is not writable. + } + PROCEDURE XPLMSetDatad( + inDataRef : XPLMDataRef; + inValue : Real); + cdecl; external XPLM_DLL; + + { + XPLMGetDatavi + + Read a part of an integer array dataref. If you pass NULL for outValues, + the routine will return the size of the array, ignoring inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatavi( + inDataRef : XPLMDataRef; + outValues : PInteger; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatavi + + Write part or all of an integer array dataref. The values passed by + inValues are written into the dataref starting at inOffset. Up to inCount + values are written; however if the values would write "off the end" of the + dataref array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatavi( + inDataRef : XPLMDataRef; + inValues : PInteger; + inoffset : Integer; + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDatavf + + Read a part of a single precision floating point array dataref. If you pass + NULL for outVaules, the routine will return the size of the array, ignoring + inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatavf( + inDataRef : XPLMDataRef; + outValues : PSingle; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatavf + + Write part or all of a single precision floating point array dataref. The + values passed by inValues are written into the dataref starting at + inOffset. Up to inCount values are written; however if the values would + write "off the end" of the dataref array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatavf( + inDataRef : XPLMDataRef; + inValues : PSingle; + inoffset : Integer; + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetDatab + + Read a part of a byte array dataref. If you pass NULL for outVaules, the + routine will return the size of the array, ignoring inOffset and inMax. + + If outValues is not NULL, then up to inMax values are copied from the + dataref into outValues, starting at inOffset in the dataref. If inMax + + inOffset is larger than the size of the dataref, less than inMax values + will be copied. The number of values copied is returned. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + FUNCTION XPLMGetDatab( + inDataRef : XPLMDataRef; + outValue : pointer; { Can be nil } + inOffset : Integer; + inMaxBytes : Integer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDatab + + Write part or all of a byte array dataref. The values passed by inValues + are written into the dataref starting at inOffset. Up to inCount values are + written; however if the values would write "off the end" of the dataref + array, then fewer values are written. + + Note: the semantics of array datarefs are entirely implemented by the + plugin (or X-Plane) that provides the dataref, not the SDK itself; the + above description is how these datarefs are intended to work, but a rogue + plugin may have different behavior. + } + PROCEDURE XPLMSetDatab( + inDataRef : XPLMDataRef; + inValue : pointer; + inOffset : Integer; + inLength : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * PUBLISHING YOUR PLUGIN'S DATA + ___________________________________________________________________________} +{ + These functions allow you to create data references that other plug-ins and + X-Plane can access via the above data access APIs. Data references + published by other plugins operate the same as ones published by X-Plane in + all manners except that your data reference will not be available to other + plugins if/when your plugin is disabled. + + You share data by registering data provider callback functions. When a + plug-in requests your data, these callbacks are then called. You provide + one callback to return the value when a plugin 'reads' it and another to + change the value when a plugin 'writes' it. + + Important: you must pick a prefix for your datarefs other than "sim/" - + this prefix is reserved for X-Plane. The X-Plane SDK website contains a + registry where authors can select a unique first word for dataref names, to + prevent dataref collisions between plugins. +} + + + { + XPLMGetDatai_f + + Data provider function pointers. + + These define the function pointers you provide to get or set data. Note + that you are passed a generic pointer for each one. This is the same + pointer you pass in your register routine; you can use it to locate plugin + variables, etc. + + The semantics of your callbacks are the same as the dataref accessor above + - basically routines like XPLMGetDatai are just pass-throughs from a caller + to your plugin. Be particularly mindful in implementing array dataref + read-write accessors; you are responsible for avoiding overruns, supporting + offset read/writes, and handling a read with a NULL buffer. + } +TYPE + XPLMGetDatai_f = FUNCTION( + inRefcon : pointer) : Integer; cdecl; + + { + XPLMSetDatai_f + } + XPLMSetDatai_f = PROCEDURE( + inRefcon : pointer; + inValue : Integer); cdecl; + + { + XPLMGetDataf_f + } + XPLMGetDataf_f = FUNCTION( + inRefcon : pointer) : Single; cdecl; + + { + XPLMSetDataf_f + } + XPLMSetDataf_f = PROCEDURE( + inRefcon : pointer; + inValue : Single); cdecl; + + { + XPLMGetDatad_f + } + XPLMGetDatad_f = FUNCTION( + inRefcon : pointer) : Real; cdecl; + + { + XPLMSetDatad_f + } + XPLMSetDatad_f = PROCEDURE( + inRefcon : pointer; + inValue : Real); cdecl; + + { + XPLMGetDatavi_f + } + XPLMGetDatavi_f = FUNCTION( + inRefcon : pointer; + outValues : PInteger; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; cdecl; + + { + XPLMSetDatavi_f + } + XPLMSetDatavi_f = PROCEDURE( + inRefcon : pointer; + inValues : PInteger; + inOffset : Integer; + inCount : Integer); cdecl; + + { + XPLMGetDatavf_f + } + XPLMGetDatavf_f = FUNCTION( + inRefcon : pointer; + outValues : PSingle; { Can be nil } + inOffset : Integer; + inMax : Integer) : Integer; cdecl; + + { + XPLMSetDatavf_f + } + XPLMSetDatavf_f = PROCEDURE( + inRefcon : pointer; + inValues : PSingle; + inOffset : Integer; + inCount : Integer); cdecl; + + { + XPLMGetDatab_f + } + XPLMGetDatab_f = FUNCTION( + inRefcon : pointer; + outValue : pointer; { Can be nil } + inOffset : Integer; + inMaxLength : Integer) : Integer; cdecl; + + { + XPLMSetDatab_f + } + XPLMSetDatab_f = PROCEDURE( + inRefcon : pointer; + inValue : pointer; + inOffset : Integer; + inLength : Integer); cdecl; + + { + XPLMRegisterDataAccessor + + This routine creates a new item of data that can be read and written. Pass + in the data's full name for searching, the type(s) of the data for + accessing, and whether the data can be written to. For each data type you + support, pass in a read accessor function and a write accessor function if + necessary. Pass NULL for data types you do not support or write accessors + if you are read-only. + + You are returned a data ref for the new item of data created. You can use + this data ref to unregister your data later or read or write from it. + } + FUNCTION XPLMRegisterDataAccessor( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inIsWritable : Integer; + inReadInt : XPLMGetDatai_f; + inWriteInt : XPLMSetDatai_f; + inReadFloat : XPLMGetDataf_f; + inWriteFloat : XPLMSetDataf_f; + inReadDouble : XPLMGetDatad_f; + inWriteDouble : XPLMSetDatad_f; + inReadIntArray : XPLMGetDatavi_f; + inWriteIntArray : XPLMSetDatavi_f; + inReadFloatArray : XPLMGetDatavf_f; + inWriteFloatArray : XPLMSetDatavf_f; + inReadData : XPLMGetDatab_f; + inWriteData : XPLMSetDatab_f; + inReadRefcon : pointer; + inWriteRefcon : pointer) : XPLMDataRef; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterDataAccessor + + Use this routine to unregister any data accessors you may have registered. + You unregister a data ref by the XPLMDataRef you get back from + registration. Once you unregister a data ref, your function pointer will + not be called anymore. + } + PROCEDURE XPLMUnregisterDataAccessor( + inDataRef : XPLMDataRef); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * SHARING DATA BETWEEN MULTIPLE PLUGINS + ___________________________________________________________________________} +{ + The data reference registration APIs from the previous section allow a + plugin to publish data in a one-owner manner; the plugin that publishes the + data reference owns the real memory that the data ref uses. This is + satisfactory for most cases, but there are also cases where plugnis need to + share actual data. + + With a shared data reference, no one plugin owns the actual memory for the + data reference; the plugin SDK allocates that for you. When the first + plugin asks to 'share' the data, the memory is allocated. When the data is + changed, every plugin that is sharing the data is notified. + + Shared data references differ from the 'owned' data references from the + previous section in a few ways: + + * With shared data references, any plugin can create the data reference; + with owned plugins one plugin must create the data reference and others + subscribe. (This can be a problem if you don't know which set of plugins + will be present). + + * With shared data references, every plugin that is sharing the data is + notified when the data is changed. With owned data references, only the + one owner is notified when the data is changed. + + * With shared data references, you cannot access the physical memory of the + data reference; you must use the XPLMGet... and XPLMSet... APIs. With an + owned data reference, the one owning data reference can manipulate the + data reference's memory in any way it sees fit. + + Shared data references solve two problems: if you need to have a data + reference used by several plugins but do not know which plugins will be + installed, or if all plugins sharing data need to be notified when that + data is changed, use shared data references. +} + + + { + XPLMDataChanged_f + + An XPLMDataChanged_f is a callback that the XPLM calls whenever any other + plug-in modifies shared data. A refcon you provide is passed back to help + identify which data is being changed. In response, you may want to call one + of the XPLMGetDataxxx routines to find the new value of the data. + } +TYPE + XPLMDataChanged_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMShareData + + This routine connects a plug-in to shared data, creating the shared data if + necessary. inDataName is a standard path for the data ref, and inDataType + specifies the type. This function will create the data if it does not + exist. If the data already exists but the type does not match, an error is + returned, so it is important that plug-in authors collaborate to establish + public standards for shared data. + + If a notificationFunc is passed in and is not NULL, that notification + function will be called whenever the data is modified. The notification + refcon will be passed to it. This allows your plug-in to know which shared + data was changed if multiple shared data are handled by one callback, or if + the plug-in does not use global variables. + + A one is returned for successfully creating or finding the shared data; a + zero if the data already exists but is of the wrong type. + } + FUNCTION XPLMShareData( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inNotificationFunc : XPLMDataChanged_f; + inNotificationRefcon: pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnshareData + + This routine removes your notification function for shared data. Call it + when done with the data to stop receiving change notifications. Arguments + must match XPLMShareData. The actual memory will not necessarily be freed, + since other plug-ins could be using it. + } + FUNCTION XPLMUnshareData( + inDataName : XPLMString; + inDataType : XPLMDataTypeID; + inNotificationFunc : XPLMDataChanged_f; + inNotificationRefcon: pointer) : Integer; + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDefs.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDefs.pas new file mode 100644 index 0000000..b614085 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDefs.pas @@ -0,0 +1,438 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDefs; +INTERFACE +{ + This file is contains the cross-platform and basic definitions for the + X-Plane SDK. + + The preprocessor macros APL and IBM must be defined to specify the + compilation target; define APL to 1 and IBM 0 to compile on Macintosh and + APL to 0 and IBM to 1 for Windows. You must specify these macro definitions + before including XPLMDefs.h or any other XPLM headers. You can do this + using the -D command line option or a preprocessor header. +} + + {$A4} +{$IFDEF LINUX} + {$DEFINE KYLIX} +{$ENDIF} +TYPE +{$IFNDEF DELPHI} +{$IFNDEF KYLIX} + Pchar = ^char; + Ppchar = ^Pchar; + Psingle = ^single; + Pinteger = ^integer; +{$ENDIF} +{$ENDIF} + Preal = ^real; + Plongint = ^longint; +{___________________________________________________________________________ + * DLL Definitions + ___________________________________________________________________________} +{ + These definitions control the importing and exporting of functions within + the DLL. + + You can prefix your five required callbacks with the PLUGIN_API macro to + declare them as exported C functions. The XPLM_API macro identifies + functions that are provided to you via the plugin SDK. (Link against + XPLM.lib to use these functions.) +} + + + +{___________________________________________________________________________ + * GLOBAL DEFINITIONS + ___________________________________________________________________________} +{ + These definitions are used in all parts of the SDK. +} + + +TYPE + { + XPLMPluginID + + Each plug-in is identified by a unique integer ID. This ID can be used to + disable or enable a plug-in, or discover what plug-in is 'running' at the + time. A plug-in ID is unique within the currently running instance of + X-Plane unless plug-ins are reloaded. Plug-ins may receive a different + unique ID each time they are loaded. This includes the unloading and + reloading of plugins that are part of the user's aircraft. + + For persistent identification of plug-ins, use XPLMFindPluginBySignature in + XPLMUtiltiies.h + + -1 indicates no plug-in. + } + XPLMPluginID = Integer; + PXPLMPluginID = ^XPLMPluginID; + +CONST + { No plugin. } + XPLM_NO_PLUGIN_ID = (-1); + + { X-Plane itself } + XPLM_PLUGIN_XPLANE = (0); + + { The current XPLM revision is 4.00 (400). } + kXPLM_Version = (400); + + { + XPLMKeyFlags + + These bitfields define modifier keys in a platform independent way. When a + key is pressed, a series of messages are sent to your plugin. The down + flag is set in the first of these messages, and the up flag in the last. + While the key is held down, messages are sent with neither to indicate that + the key is being held down as a repeated character. + + The control flag is mapped to the control flag on Macintosh and PC. + Generally X-Plane uses the control key and not the command key on + Macintosh, providing a consistent interface across platforms that does not + necessarily match the Macintosh user interface guidelines. There is not + yet a way for plugins to access the Macintosh control keys without using + #ifdefed code. + } +TYPE + XPLMKeyFlags = ( + { The shift key is down } + xplm_ShiftFlag = 1 + + { The option or alt key is down } + ,xplm_OptionAltFlag = 2 + + { The control key is down* } + ,xplm_ControlFlag = 4 + + { The key is being pressed down } + ,xplm_DownFlag = 8 + + { The key is being released } + ,xplm_UpFlag = 16 + + ); + PXPLMKeyFlags = ^XPLMKeyFlags; + +{___________________________________________________________________________ + * ASCII CONTROL KEY CODES + ___________________________________________________________________________} +{ + These definitions define how various control keys are mapped to ASCII key + codes. Not all key presses generate an ASCII value, so plugin code should + be prepared to see null characters come from the keyboard...this usually + represents a key stroke that has no equivalent ASCII, like a page-down + press. Use virtual key codes to find these key strokes. + + ASCII key codes take into account modifier keys; shift keys will affect + capitals and punctuation; control key combinations may have no vaild ASCII + and produce NULL. To detect control-key combinations, use virtual key + codes, not ASCII keys. +} + + +CONST + XPLM_KEY_RETURN = 13; + + XPLM_KEY_ESCAPE = 27; + + XPLM_KEY_TAB = 9; + + XPLM_KEY_DELETE = 8; + + XPLM_KEY_LEFT = 28; + + XPLM_KEY_RIGHT = 29; + + XPLM_KEY_UP = 30; + + XPLM_KEY_DOWN = 31; + + XPLM_KEY_0 = 48; + + XPLM_KEY_1 = 49; + + XPLM_KEY_2 = 50; + + XPLM_KEY_3 = 51; + + XPLM_KEY_4 = 52; + + XPLM_KEY_5 = 53; + + XPLM_KEY_6 = 54; + + XPLM_KEY_7 = 55; + + XPLM_KEY_8 = 56; + + XPLM_KEY_9 = 57; + + XPLM_KEY_DECIMAL = 46; + +{___________________________________________________________________________ + * VIRTUAL KEY CODES + ___________________________________________________________________________} +{ + These are cross-platform defines for every distinct keyboard press on the + computer. Every physical key on the keyboard has a virtual key code. So + the "two" key on the top row of the main keyboard has a different code from + the "two" key on the numeric key pad. But the 'w' and 'W' character are + indistinguishable by virtual key code because they are the same physical + key (one with and one without the shift key). + + Use virtual key codes to detect keystrokes that do not have ASCII + equivalents, allow the user to map the numeric keypad separately from the + main keyboard, and detect control key and other modifier-key combinations + that generate ASCII control key sequences (many of which are not available + directly via character keys in the SDK). + + To assign virtual key codes we started with the Microsoft set but made some + additions and changes. A few differences: + + 1. Modifier keys are not available as virtual key codes. You cannot get + distinct modifier press and release messages. Please do not try to use + modifier keys as regular keys; doing so will almost certainly interfere + with users' abilities to use the native X-Plane key bindings. + 2. Some keys that do not exist on both Mac and PC keyboards are removed. + 3. Do not assume that the values of these keystrokes are interchangeable + with MS v-keys. +} + + +CONST + XPLM_VK_BACK = $08; + + XPLM_VK_TAB = $09; + + XPLM_VK_CLEAR = $0C; + + XPLM_VK_RETURN = $0D; + + XPLM_VK_ESCAPE = $1B; + + XPLM_VK_SPACE = $20; + + XPLM_VK_PRIOR = $21; + + XPLM_VK_NEXT = $22; + + XPLM_VK_END = $23; + + XPLM_VK_HOME = $24; + + XPLM_VK_LEFT = $25; + + XPLM_VK_UP = $26; + + XPLM_VK_RIGHT = $27; + + XPLM_VK_DOWN = $28; + + XPLM_VK_SELECT = $29; + + XPLM_VK_PRINT = $2A; + + XPLM_VK_EXECUTE = $2B; + + XPLM_VK_SNAPSHOT = $2C; + + XPLM_VK_INSERT = $2D; + + XPLM_VK_DELETE = $2E; + + XPLM_VK_HELP = $2F; + + { XPLM_VK_0 thru XPLM_VK_9 are the same as ASCII '0' thru '9' (0x30 - 0x39) } + XPLM_VK_0 = $30; + + XPLM_VK_1 = $31; + + XPLM_VK_2 = $32; + + XPLM_VK_3 = $33; + + XPLM_VK_4 = $34; + + XPLM_VK_5 = $35; + + XPLM_VK_6 = $36; + + XPLM_VK_7 = $37; + + XPLM_VK_8 = $38; + + XPLM_VK_9 = $39; + + { XPLM_VK_A thru XPLM_VK_Z are the same as ASCII 'A' thru 'Z' (0x41 - 0x5A) } + XPLM_VK_A = $41; + + XPLM_VK_B = $42; + + XPLM_VK_C = $43; + + XPLM_VK_D = $44; + + XPLM_VK_E = $45; + + XPLM_VK_F = $46; + + XPLM_VK_G = $47; + + XPLM_VK_H = $48; + + XPLM_VK_I = $49; + + XPLM_VK_J = $4A; + + XPLM_VK_K = $4B; + + XPLM_VK_L = $4C; + + XPLM_VK_M = $4D; + + XPLM_VK_N = $4E; + + XPLM_VK_O = $4F; + + XPLM_VK_P = $50; + + XPLM_VK_Q = $51; + + XPLM_VK_R = $52; + + XPLM_VK_S = $53; + + XPLM_VK_T = $54; + + XPLM_VK_U = $55; + + XPLM_VK_V = $56; + + XPLM_VK_W = $57; + + XPLM_VK_X = $58; + + XPLM_VK_Y = $59; + + XPLM_VK_Z = $5A; + + XPLM_VK_NUMPAD0 = $60; + + XPLM_VK_NUMPAD1 = $61; + + XPLM_VK_NUMPAD2 = $62; + + XPLM_VK_NUMPAD3 = $63; + + XPLM_VK_NUMPAD4 = $64; + + XPLM_VK_NUMPAD5 = $65; + + XPLM_VK_NUMPAD6 = $66; + + XPLM_VK_NUMPAD7 = $67; + + XPLM_VK_NUMPAD8 = $68; + + XPLM_VK_NUMPAD9 = $69; + + XPLM_VK_MULTIPLY = $6A; + + XPLM_VK_ADD = $6B; + + XPLM_VK_SEPARATOR = $6C; + + XPLM_VK_SUBTRACT = $6D; + + XPLM_VK_DECIMAL = $6E; + + XPLM_VK_DIVIDE = $6F; + + XPLM_VK_F1 = $70; + + XPLM_VK_F2 = $71; + + XPLM_VK_F3 = $72; + + XPLM_VK_F4 = $73; + + XPLM_VK_F5 = $74; + + XPLM_VK_F6 = $75; + + XPLM_VK_F7 = $76; + + XPLM_VK_F8 = $77; + + XPLM_VK_F9 = $78; + + XPLM_VK_F10 = $79; + + XPLM_VK_F11 = $7A; + + XPLM_VK_F12 = $7B; + + XPLM_VK_F13 = $7C; + + XPLM_VK_F14 = $7D; + + XPLM_VK_F15 = $7E; + + XPLM_VK_F16 = $7F; + + XPLM_VK_F17 = $80; + + XPLM_VK_F18 = $81; + + XPLM_VK_F19 = $82; + + XPLM_VK_F20 = $83; + + XPLM_VK_F21 = $84; + + XPLM_VK_F22 = $85; + + XPLM_VK_F23 = $86; + + XPLM_VK_F24 = $87; + + { The following definitions are extended and are not based on the Microsoft } + { key set. } + XPLM_VK_EQUAL = $B0; + + XPLM_VK_MINUS = $B1; + + XPLM_VK_RBRACE = $B2; + + XPLM_VK_LBRACE = $B3; + + XPLM_VK_QUOTE = $B4; + + XPLM_VK_SEMICOLON = $B5; + + XPLM_VK_BACKSLASH = $B6; + + XPLM_VK_COMMA = $B7; + + XPLM_VK_SLASH = $B8; + + XPLM_VK_PERIOD = $B9; + + XPLM_VK_BACKQUOTE = $BA; + + XPLM_VK_ENTER = $BB; + + XPLM_VK_NUMPAD_ENT = $BC; + + XPLM_VK_NUMPAD_EQ = $BD; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDisplay.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDisplay.pas new file mode 100644 index 0000000..ee4242c --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMDisplay.pas @@ -0,0 +1,1630 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMDisplay; +INTERFACE +{ + This API provides the basic hooks to draw in X-Plane and create user + interface. All X-Plane drawing is done in OpenGL. The X-Plane plug-in + manager takes care of properly setting up the OpenGL context and matrices. + You do not decide when in your code's execution to draw; X-Plane tells you + (via callbacks) when it is ready to have your plugin draw. + + X-Plane's drawing strategy is straightforward: every "frame" the screen is + rendered by drawing the 3-D scene (dome, ground, objects, airplanes, etc.) + and then drawing the cockpit on top of it. Alpha blending is used to + overlay the cockpit over the world (and the gauges over the panel, etc.). + X-Plane user interface elements (including windows like the map, the main + menu, etc.) are then drawn on top of the cockpit. + + There are two ways you can draw: directly and in a window. + + Direct drawing (deprecated!---more on that below) involves drawing to the + screen before or after X-Plane finishes a phase of drawing. When you draw + directly, you can specify whether X-Plane is to complete this phase or not. + This allows you to do three things: draw before X-Plane does (under it), + draw after X-Plane does (over it), or draw instead of X-Plane. + + To draw directly, you register a callback and specify which phase you want + to intercept. The plug-in manager will call you over and over to draw that + phase. + + Direct drawing allows you to override scenery, panels, or anything. Note + that you cannot assume that you are the only plug-in drawing at this phase. + + Direct drawing is deprecated; at some point in the X-Plane 11 run, it will + likely become unsupported entirely as X-Plane transitions from OpenGL to + modern graphics API backends (e.g., Vulkan, Metal, etc.). In the long term, + plugins should use the XPLMInstance API for drawing 3-D objects---this will + be much more efficient than general 3-D OpenGL drawing, and it will + actually be supported by the new graphics backends. We do not yet know what + the post-transition API for generic 3-D drawing will look like (if it + exists at all). + + In contrast to direct drawing, window drawing provides a higher level + functionality. With window drawing, you create a 2-D window that takes up a + portion of the screen. Window drawing is always two dimensional. Window + drawing is front-to-back controlled; you can specify that you want your + window to be brought on top, and other plug-ins may put their window on top + of you. Window drawing also allows you to sign up for key presses and + receive mouse clicks. + + Drawing into the screen of an avionics device, like a GPS or a Primary + Flight Display, is a way to extend or replace X-Plane's avionics. Most + screens can be displayed both in a 3d cockpit or + 2d panel, and also in separate popup windows. By installing drawing + callbacks for a certain avionics device, you can change or extend the + appearance of that device regardless whether it's installed in a 3d + cockpit or used in a separate display for home cockpits because you leave + the window managing to X-Plane. + + There are three ways to get keystrokes: + + 1. If you create a window, the window can take keyboard focus. It will + then receive all keystrokes. If no window has focus, X-Plane receives + keystrokes. Use this to implement typing in dialog boxes, etc. Only + one window may have focus at a time; your window will be notified if it + loses focus. + 2. If you need low level access to the keystroke stream, install a key + sniffer. Key sniffers can be installed above everything or right in + front of the sim. + 3. If you would like to associate key strokes with commands/functions in + your plug-in, you should simply register a command (via + XPLMCreateCommand()) and allow users to bind whatever key they choose to + that command. Another (now deprecated) method of doing so is to use a + hot key---a key-specific callback. Hotkeys are sent based on virtual + key strokes, so any key may be distinctly mapped with any modifiers. + Hot keys can be remapped by other plug-ins. As a plug-in, you don't + have to worry about what your hot key ends up mapped to; other plug-ins + may provide a UI for remapping keystrokes. So hotkeys allow a user to + resolve conflicts and customize keystrokes. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * DRAWING CALLBACKS + ___________________________________________________________________________} +{ + Basic drawing callbacks, for low level intercepting of X-Plane's render + loop. The purpose of drawing callbacks is to provide targeted additions or + replacements to X-Plane's graphics environment (for example, to add extra + custom objects, or replace drawing of the AI aircraft). Do not assume that + the drawing callbacks will be called in the order implied by the + enumerations. Also do not assume that each drawing phase ends before + another begins; they may be nested. + + Note that all APIs in this section are deprecated, and will likely be + removed during the X-Plane 11 run as part of the transition to + Vulkan/Metal/etc. See the XPLMInstance API for future-proof drawing of 3-D + objects. +} + + + { + XPLMDrawingPhase + + This constant indicates which part of drawing we are in. Drawing is done + from the back to the front. We get a callback before or after each item. + Metaphases provide access to the beginning and end of the 3d (scene) and + 2d (cockpit) drawing in a manner that is independent of new phases added + via X-Plane implementation. + + **NOTE**: As of XPLM302 the legacy 3D drawing phases (xplm_Phase_FirstScene + to xplm_Phase_LastScene) are deprecated. When running under X-Plane 11.50 + with the modern Vulkan or Metal backend, X-Plane will no longer call + these drawing phases. There is a new drawing phase, xplm_Phase_Modern3D, + which is supported under OpenGL and Vulkan which is called out roughly + where the old before xplm_Phase_Airplanes phase was for blending. This + phase is *NOT* supported under Metal and comes with potentially + substantial performance overhead. Please do *NOT* opt into this phase if + you don't do any actual drawing that requires the depth buffer in some + way! + + **WARNING**: As X-Plane's scenery evolves, some drawing phases may cease to + exist and new ones may be invented. If you need a particularly specific + use of these codes, consult Austin and/or be prepared to revise your code + as X-Plane evolves. + } +TYPE + XPLMDrawingPhase = ( +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. This is the earliest point at which you can draw } + { in 3-d. } + xplm_Phase_FirstScene = 0 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing of land and water. } + ,xplm_Phase_Terrain = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing runways and other airport detail. } + ,xplm_Phase_Airports = 10 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. Drawing roads, trails, trains, etc. } + ,xplm_Phase_Vectors = 15 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. 3-d objects (houses, smokestacks, etc. } + ,xplm_Phase_Objects = 20 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. External views of airplanes, both yours and the } + { AI aircraft. } + ,xplm_Phase_Airplanes = 25 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated as of XPLM302. This is the last point at which you can draw in } + { 3-d. } + ,xplm_Phase_LastScene = 30 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM302} + { A chance to do modern 3D drawing. } + ,xplm_Phase_Modern3D = 31 +{$ENDIF XPLM302} + + { This is the first phase where you can draw in 2-d. } + ,xplm_Phase_FirstCockpit = 35 + + { The non-moving parts of the aircraft panel. } + ,xplm_Phase_Panel = 40 + + { The moving parts of the aircraft panel. } + ,xplm_Phase_Gauges = 45 + + { Floating windows from plugins. } + ,xplm_Phase_Window = 50 + + { The last chance to draw in 2d. } + ,xplm_Phase_LastCockpit = 55 + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMap3D = 100 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMap2D = 101 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { Removed as of XPLM300; Use the full-blown XPLMMap API instead. } + ,xplm_Phase_LocalMapProfile = 102 +{$ENDIF XPLM200} + + ); + PXPLMDrawingPhase = ^XPLMDrawingPhase; + + { + XPLMDrawCallback_f + + This is the prototype for a low level drawing callback. You are passed in + the phase and whether it is before or after. If you are before the phase, + return 1 to let X-Plane draw or 0 to suppress X-Plane drawing. If you are + after the phase the return value is ignored. + + Refcon is a unique value that you specify when registering the callback, + allowing you to slip a pointer to your own data to the callback. + + Upon entry the OpenGL context will be correctly set up for you and OpenGL + will be in 'local' coordinates for 3d drawing and panel coordinates for 2d + drawing. The OpenGL state (texturing, etc.) will be unknown. + } + XPLMDrawCallback_f = FUNCTION( + inPhase : XPLMDrawingPhase; + inIsBefore : Integer; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMRegisterDrawCallback + + This routine registers a low level drawing callback. Pass in the phase you + want to be called for and whether you want to be called before or after. + This routine returns 1 if the registration was successful, or 0 if the + phase does not exist in this version of X-Plane. You may register a + callback multiple times for the same or different phases as long as the + refcon is unique each time. + + Note that this function will likely be removed during the X-Plane 11 run as + part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + future-proof drawing of 3-D objects. + } + FUNCTION XPLMRegisterDrawCallback( + inCallback : XPLMDrawCallback_f; + inPhase : XPLMDrawingPhase; + inWantsBefore : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterDrawCallback + + This routine unregisters a draw callback. You must unregister a callback + for each time you register a callback if you have registered it multiple + times with different refcons. The routine returns 1 if it can find the + callback to unregister, 0 otherwise. + + Note that this function will likely be removed during the X-Plane 11 run as + part of the transition to Vulkan/Metal/etc. See the XPLMInstance API for + future-proof drawing of 3-D objects. + } + FUNCTION XPLMUnregisterDrawCallback( + inCallback : XPLMDrawCallback_f; + inPhase : XPLMDrawingPhase; + inWantsBefore : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM400} +{___________________________________________________________________________ + * AVIONICS API + ___________________________________________________________________________} +{ + Drawing callbacks for before and after X-Plane draws the instrument screen + can be registered for every cockpit device. If the user plane does not + have the device installed, your callback will not be called! Use the + return value to enable or disable X-Plane's drawing. By drawing into the + framebuffer of the avionics device, your modifications will be visible + regardless whether the device's screen is in a 3d cockpit or a popup + window. +} + + + { + XPLMDeviceID + + This constant indicates the device we want to override or enhance. We can + get a callback before or after each item. + } +TYPE + XPLMDeviceID = ( + { GNS430, pilot side. } + xplm_device_GNS430_1 = 0 + + { GNS430, copilot side. } + ,xplm_device_GNS430_2 = 1 + + { GNS530, pilot side. } + ,xplm_device_GNS530_1 = 2 + + { GNS530, copilot side. } + ,xplm_device_GNS530_2 = 3 + + { generic airliner CDU, pilot side. } + ,xplm_device_CDU739_1 = 4 + + { generic airliner CDU, copilot side. } + ,xplm_device_CDU739_2 = 5 + + { G1000 Primary Flight Display, pilot side. } + ,xplm_device_G1000_PFD_1 = 6 + + { G1000 Multifunction Display. } + ,xplm_device_G1000_MFD = 7 + + { G1000 Primary Flight Display, copilot side. } + ,xplm_device_G1000_PFD_2 = 8 + + { Primus CDU, pilot side. } + ,xplm_device_CDU815_1 = 9 + + { Primus CDU, copilot side. } + ,xplm_device_CDU815_2 = 10 + + { Primus Primary Flight Display, pilot side. } + ,xplm_device_Primus_PFD_1 = 11 + + { Primus Primary Flight Display, copilot side. } + ,xplm_device_Primus_PFD_2 = 12 + + { Primus Multifunction Display, pilot side. } + ,xplm_device_Primus_MFD_1 = 13 + + { Primus Multifunction Display, copilot side. } + ,xplm_device_Primus_MFD_2 = 14 + + { Primus Multifunction Display, central. } + ,xplm_device_Primus_MFD_3 = 15 + + { Primus Radio Management Unit, pilot side. } + ,xplm_device_Primus_RMU_1 = 16 + + { Primus Radio Management Unit, copilot side. } + ,xplm_device_Primus_RMU_2 = 17 + + ); + PXPLMDeviceID = ^XPLMDeviceID; + + { + XPLMAvionicsCallback_f + + This is the prototype for your drawing callback. You are passed in the + device you are enhancing/replacing, and whether it is before or after + X-Plane drawing. If you are before X-Plane, return 1 to let X-Plane draw or + 0 to suppress X-Plane drawing. If you are after the phase the return value + is ignored. + + Refcon is a unique value that you specify when registering the callback, + allowing you to slip a pointer to your own data to the callback. + + Upon entry the OpenGL context will be correctly set up for you and OpenGL + will be in panel coordinates for 2d drawing. The OpenGL state (texturing, + etc.) will be unknown. + } + XPLMAvionicsCallback_f = FUNCTION( + inDeviceID : XPLMDeviceID; + inIsBefore : Integer; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMAvionicsID + + This is an opaque identifier for an avionics display that you enhance or + replace. When you register your callbacks (via + XPLMRegisterAvionicsCallbacksEx()), you will specify callbacks to handle + drawing, and get back such a handle. + } + XPLMAvionicsID = pointer; + PXPLMAvionicsID = ^XPLMAvionicsID; + + { + XPLMCustomizeAvionics_t + + The XPLMCustomizeAvionics_t structure defines all of the parameters used to + replace or enhance avionics for using XPLMRegisterAvionicsCallbacksEx(). + The structure will be expanded in future SDK APIs to include more features. + Always set the structSize member to the size of your struct in bytes! + } + XPLMCustomizeAvionics_t = RECORD + { Used to inform XPLMRegisterAvionicsCallbacksEx() of the SDK version you } + { compiled against; should always be set to sizeof(XPLMCustomizeAvionics_t) } + structSize : Integer; + { Which avionics device you want your drawing applied to. } + deviceId : XPLMDeviceID; + { The draw callback to be called before X-Plane draws. } + drawCallbackBefore : XPLMAvionicsCallback_f; + { The draw callback to be called after X-Plane has drawn. } + drawCallbackAfter : XPLMAvionicsCallback_f; + { A reference which will be passed into each of your draw callbacks. Use this} + { to pass information to yourself as needed. } + refcon : pointer; + END; + PXPLMCustomizeAvionics_t = ^XPLMCustomizeAvionics_t; + + { + XPLMRegisterAvionicsCallbacksEx + + This routine registers your callbacks for a device. This returns a handle. + If the returned handle is NULL, there was a problem interpreting your + input, most likely the struct size was wrong for your SDK version. If the + returned handle is not NULL, your callbacks will be called according to + schedule as long as your plugin is not deactivated, or unloaded, or your + call XPLMUnregisterAvionicsCallbacks(). + } + FUNCTION XPLMRegisterAvionicsCallbacksEx( + inParams : PXPLMCustomizeAvionics_t) : XPLMAvionicsID; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterAvionicsCallbacks + + This routine unregisters your callbacks for a device. They will no longer + be called. + } + PROCEDURE XPLMUnregisterAvionicsCallbacks( + inAvionicsId : XPLMAvionicsID); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM400} +{___________________________________________________________________________ + * WINDOW API + ___________________________________________________________________________} +{ + The window API provides a high-level abstraction for drawing with UI + interaction. + + Windows may operate in one of two modes: legacy (for plugins compiled + against old versions of the XPLM, as well as windows created via the + deprecated XPLMCreateWindow() function, rather than XPLMCreateWindowEx()), + or modern (for windows compiled against the XPLM300 or newer API, and + created via XPLMCreateWindowEx()). + + Modern windows have access to new X-Plane 11 windowing features, like + support for new positioning modes (including being "popped out" into their + own first-class window in the operating system). They can also optionally + be decorated in the style of X-Plane 11 windows (like the map). + + Modern windows operate in "boxel" units. A boxel ("box of pixels") is a + unit of virtual pixels which, depending on X-Plane's scaling, may + correspond to an arbitrary NxN "box" of real pixels on screen. Because + X-Plane handles this scaling automatically, you can effectively treat the + units as though you were simply drawing in pixels, and know that when + X-Plane is running with 150% or 200% scaling, your drawing will be + automatically scaled (and likewise all mouse coordinates, screen bounds, + etc. will also be auto-scaled). + + In contrast, legacy windows draw in true screen pixels, and thus tend to + look quite small when X-Plane is operating in a scaled mode. + + Legacy windows have their origin in the lower left of the main X-Plane + window. In contrast, since modern windows are not constrained to the main + window, they have their origin in the lower left of the entire global + desktop space, and the lower left of the main X-Plane window is not + guaranteed to be (0, 0). In both cases, x increases as you move left, and y + increases as you move up. +} + + +TYPE + { + XPLMWindowID + + This is an opaque identifier for a window. You use it to control your + window. When you create a window (via either XPLMCreateWindow() or + XPLMCreateWindowEx()), you will specify callbacks to handle drawing, mouse + interaction, etc. + } + XPLMWindowID = pointer; + PXPLMWindowID = ^XPLMWindowID; + + { + XPLMDrawWindow_f + + A callback to handle 2-D drawing of your window. You are passed in your + window and its refcon. Draw the window. You can use other XPLM functions + from this header to find the current dimensions of your window, etc. When + this callback is called, the OpenGL context will be set properly for 2-D + window drawing. + + **Note**: Because you are drawing your window over a background, you can + make a translucent window easily by simply not filling in your entire + window's bounds. + } + XPLMDrawWindow_f = PROCEDURE( + inWindowID : XPLMWindowID; + inRefcon : pointer); cdecl; + + { + XPLMHandleKey_f + + This function is called when a key is pressed or keyboard focus is taken + away from your window. If losingFocus is 1, you are losing the keyboard + focus, otherwise a key was pressed and inKey contains its character. + + The window ID passed in will be your window for key presses, or the other + window taking focus when losing focus. Note that in the modern plugin + system, often focus is taken by the window manager itself; for this resaon, + the window ID may be zero when losing focus, and you should not write code + that depends onit. + + The refcon passed in will be the one from registration, for both key + presses and losing focus. + + Warning: this API declares virtual keys as a signed character; however the + VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + to an unsigned char to get correct comparisons in C. + } + XPLMHandleKey_f = PROCEDURE( + inWindowID : XPLMWindowID; + inKey : XPLMChar; + inFlags : XPLMKeyFlags; + inVirtualKey : XPLMChar; + inRefcon : pointer; + losingFocus : Integer); cdecl; + + { + XPLMMouseStatus + + When the mouse is clicked, your mouse click routine is called repeatedly. + It is first called with the mouse down message. It is then called zero or + more times with the mouse-drag message, and finally it is called once with + the mouse up message. All of these messages will be directed to the same + window; you are guaranteed to not receive a drag or mouse-up event without + first receiving the corresponding mouse-down. + } + XPLMMouseStatus = ( + xplm_MouseDown = 1 + + ,xplm_MouseDrag = 2 + + ,xplm_MouseUp = 3 + + ); + PXPLMMouseStatus = ^XPLMMouseStatus; + + { + XPLMHandleMouseClick_f + + You receive this call for one of three events: + + - when the user clicks the mouse button down + - (optionally) when the user drags the mouse after a down-click, but before + the up-click + - when the user releases the down-clicked mouse button. + + You receive the x and y of the click, your window, and a refcon. Return 1 + to consume the click, or 0 to pass it through. + + WARNING: passing clicks through windows (as of this writing) causes mouse + tracking problems in X-Plane; do not use this feature! + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleMouseClick_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + inMouse : XPLMMouseStatus; + inRefcon : pointer) : Integer; cdecl; + +{$IFDEF XPLM200} + { + XPLMCursorStatus + + XPLMCursorStatus describes how you would like X-Plane to manage the cursor. + See XPLMHandleCursor_f for more info. + } +TYPE + XPLMCursorStatus = ( + { X-Plane manages the cursor normally, plugin does not affect the cusrsor. } + xplm_CursorDefault = 0 + + { X-Plane hides the cursor. } + ,xplm_CursorHidden = 1 + + { X-Plane shows the cursor as the default arrow. } + ,xplm_CursorArrow = 2 + + { X-Plane shows the cursor but lets you select an OS cursor. } + ,xplm_CursorCustom = 3 + + ); + PXPLMCursorStatus = ^XPLMCursorStatus; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMHandleCursor_f + + The SDK calls your cursor status callback when the mouse is over your + plugin window. Return a cursor status code to indicate how you would like + X-Plane to manage the cursor. If you return xplm_CursorDefault, the SDK + will try lower-Z-order plugin windows, then let the sim manage the cursor. + + Note: you should never show or hide the cursor yourself---these APIs are + typically reference-counted and thus cannot safely and predictably be used + by the SDK. Instead return one of xplm_CursorHidden to hide the cursor or + xplm_CursorArrow/xplm_CursorCustom to show the cursor. + + If you want to implement a custom cursor by drawing a cursor in OpenGL, use + xplm_CursorHidden to hide the OS cursor and draw the cursor using a 2-d + drawing callback (after xplm_Phase_Window is probably a good choice, but + see deprecation warnings on the drawing APIs!). If you want to use a + custom OS-based cursor, use xplm_CursorCustom to ask X-Plane to show the + cursor but not affect its image. You can then use an OS specific call like + SetThemeCursor (Mac) or SetCursor/LoadCursor (Windows). + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleCursor_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + inRefcon : pointer) : XPLMCursorStatus; cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMHandleMouseWheel_f + + The SDK calls your mouse wheel callback when one of the mouse wheels is + scrolled within your window. Return 1 to consume the mouse wheel movement + or 0 to pass them on to a lower window. (If your window appears opaque to + the user, you should consume mouse wheel scrolling even if it does + nothing.) The number of "clicks" indicates how far the wheel was turned + since the last callback. The wheel is 0 for the vertical axis or 1 for the + horizontal axis (for OS/mouse combinations that support this). + + The units for x and y values match the units used in your window. Thus, for + "modern" windows (those created via XPLMCreateWindowEx() and compiled + against the XPLM300 library), the units are boxels, while legacy windows + will get pixels. Legacy windows have their origin in the lower left of the + main X-Plane window, while modern windows have their origin in the lower + left of the global desktop space. In both cases, x increases as you move + right, and y increases as you move up. + } + XPLMHandleMouseWheel_f = FUNCTION( + inWindowID : XPLMWindowID; + x : Integer; + y : Integer; + wheel : Integer; + clicks : Integer; + inRefcon : pointer) : Integer; cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM300} + { + XPLMWindowLayer + + XPLMWindowLayer describes where in the ordering of windows X-Plane should + place a particular window. Windows in higher layers cover windows in lower + layers. So, a given window might be at the top of its particular layer, but + it might still be obscured by a window in a higher layer. (This happens + frequently when floating windows, like X-Plane's map, are covered by a + modal alert.) + + Your window's layer can only be specified when you create the window (in + the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). For this reason, + layering only applies to windows created with new X-Plane 11 GUI features. + (Windows created using the older XPLMCreateWindow(), or windows compiled + against a pre-XPLM300 version of the SDK will simply be placed in the + flight overlay window layer.) + } +TYPE + XPLMWindowLayer = ( + { The lowest layer, used for HUD-like displays while flying. } + xplm_WindowLayerFlightOverlay = 0 + + { Windows that "float" over the sim, like the X-Plane 11 map does. If you are} + { not sure which layer to create your window in, choose floating. } + ,xplm_WindowLayerFloatingWindows = 1 + + { An interruptive modal that covers the sim with a transparent black overlay } + { to draw the user's focus to the alert } + ,xplm_WindowLayerModal = 2 + + { "Growl"-style notifications that are visible in a corner of the screen, } + { even over modals } + ,xplm_WindowLayerGrowlNotifications = 3 + + ); + PXPLMWindowLayer = ^XPLMWindowLayer; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMWindowDecoration + + XPLMWindowDecoration describes how "modern" windows will be displayed. This + impacts both how X-Plane draws your window as well as certain mouse + handlers. + + Your window's decoration can only be specified when you create the window + (in the XPLMCreateWindow_t you pass to XPLMCreateWindowEx()). + } +TYPE + XPLMWindowDecoration = ( + { X-Plane will draw no decoration for your window, and apply no automatic } + { click handlers. The window will not stop click from passing through its } + { bounds. This is suitable for "windows" which request, say, the full screen } + { bounds, then only draw in a small portion of the available area. } + xplm_WindowDecorationNone = 0 + + { The default decoration for "native" windows, like the map. Provides a solid} + { background, as well as click handlers for resizing and dragging the window.} + ,xplm_WindowDecorationRoundRectangle = 1 + + { X-Plane will draw no decoration for your window, nor will it provide resize} + { handlers for your window edges, but it will stop clicks from passing } + { through your windows bounds. } + ,xplm_WindowDecorationSelfDecorated = 2 + + { Like self-decorated, but with resizing; X-Plane will draw no decoration for} + { your window, but it will stop clicks from passing through your windows } + { bounds, and provide automatic mouse handlers for resizing. } + ,xplm_WindowDecorationSelfDecoratedResizable = 3 + + ); + PXPLMWindowDecoration = ^XPLMWindowDecoration; +{$ENDIF XPLM301} + +{$IFDEF XPLM200} + { + XPLMCreateWindow_t + + The XPMCreateWindow_t structure defines all of the parameters used to + create a modern window using XPLMCreateWindowEx(). The structure will be + expanded in future SDK APIs to include more features. Always set the + structSize member to the size of your struct in bytes! + + All windows created by this function in the XPLM300 version of the API are + created with the new X-Plane 11 GUI features. This means your plugin will + get to "know" about the existence of X-Plane windows other than the main + window. All drawing and mouse callbacks for your window will occur in + "boxels," giving your windows automatic support for high-DPI scaling in + X-Plane. In addition, your windows can opt-in to decoration with the + X-Plane 11 window styling, and you can use the + XPLMSetWindowPositioningMode() API to make your window "popped out" into a + first-class operating system window. + + Note that this requires dealing with your window's bounds in "global + desktop" positioning units, rather than the traditional panel coordinate + system. In global desktop coordinates, the main X-Plane window may not have + its origin at coordinate (0, 0), and your own window may have negative + coordinates. Assuming you don't implicitly assume (0, 0) as your origin, + the only API change you should need is to start using + XPLMGetMouseLocationGlobal() rather than XPLMGetMouseLocation(), and + XPLMGetScreenBoundsGlobal() instead of XPLMGetScreenSize(). + + If you ask to be decorated as a floating window, you'll get the blue window + control bar and blue backing that you see in X-Plane 11's normal "floating" + windows (like the map). + } +TYPE + XPLMCreateWindow_t = RECORD + { Used to inform XPLMCreateWindowEx() of the SDK version you compiled } + { against; should always be set to sizeof(XPLMCreateWindow_t) } + structSize : Integer; + { Left bound, in global desktop boxels } + left : Integer; + { Top bound, in global desktop boxels } + top : Integer; + { Right bound, in global desktop boxels } + right : Integer; + { Bottom bound, in global desktop boxels } + bottom : Integer; + visible : Integer; + drawWindowFunc : XPLMDrawWindow_f; + { A callback to handle the user left-clicking within your window (or NULL to } + { ignore left clicks) } + handleMouseClickFunc : XPLMHandleMouseClick_f; + handleKeyFunc : XPLMHandleKey_f; + handleCursorFunc : XPLMHandleCursor_f; + handleMouseWheelFunc : XPLMHandleMouseWheel_f; + { A reference which will be passed into each of your window callbacks. Use } + { this to pass information to yourself as needed. } + refcon : pointer; +{$IFDEF XPLM301} + { Specifies the type of X-Plane 11-style "wrapper" you want around your } + { window, if any } + decorateAsFloatingWindow : XPLMWindowDecoration; +{$ENDIF XPLM301} +{$IFDEF XPLM300} + layer : XPLMWindowLayer; +{$ENDIF XPLM300} +{$IFDEF XPLM300} + { A callback to handle the user right-clicking within your window (or NULL to} + { ignore right clicks) } + handleRightClickFunc : XPLMHandleMouseClick_f; +{$ENDIF XPLM300} + END; + PXPLMCreateWindow_t = ^XPLMCreateWindow_t; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMCreateWindowEx + + This routine creates a new "modern" window. You pass in an + XPLMCreateWindow_t structure with all of the fields set in. You must set + the structSize of the structure to the size of the actual structure you + used. Also, you must provide functions for every callback---you may not + leave them null! (If you do not support the cursor or mouse wheel, use + functions that return the default values.) + } + FUNCTION XPLMCreateWindowEx( + inParams : PXPLMCreateWindow_t) : XPLMWindowID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + { + XPLMCreateWindow + + Deprecated as of XPLM300. + + This routine creates a new legacy window. Unlike modern windows (created + via XPLMCreateWindowEx()), legacy windows do not have access to X-Plane 11 + features like automatic scaling for high-DPI screens, native window styles, + or support for being "popped out" into first-class operating system + windows. + + Pass in the dimensions and offsets to the window's bottom left corner from + the bottom left of the screen. You can specify whether the window is + initially visible or not. Also, you pass in three callbacks to run the + window and a refcon. This function returns a window ID you can use to + refer to the new window. + + NOTE: Legacy windows do not have "frames"; you are responsible for drawing + the background and frame of the window. Higher level libraries have + routines which make this easy. + } + FUNCTION XPLMCreateWindow( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer; + inIsVisible : Integer; + inDrawCallback : XPLMDrawWindow_f; + inKeyCallback : XPLMHandleKey_f; + inMouseCallback : XPLMHandleMouseClick_f; + inRefcon : pointer) : XPLMWindowID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyWindow + + This routine destroys a window. The window's callbacks are not called + after this call. Keyboard focus is removed from the window before + destroying it. + } + PROCEDURE XPLMDestroyWindow( + inWindowID : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMGetScreenSize + + This routine returns the size of the main X-Plane OpenGL window in pixels. + This number can be used to get a rough idea of the amount of detail the + user will be able to see when drawing in 3-d. + } + PROCEDURE XPLMGetScreenSize( + outWidth : PInteger; { Can be nil } + outHeight : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetScreenBoundsGlobal + + This routine returns the bounds of the "global" X-Plane desktop, in boxels. + Unlike the non-global version XPLMGetScreenSize(), this is multi-monitor + aware. There are three primary consequences of multimonitor awareness. + + First, if the user is running X-Plane in full-screen on two or more + monitors (typically configured using one full-screen window per monitor), + the global desktop will be sized to include all X-Plane windows. + + Second, the origin of the screen coordinates is not guaranteed to be (0, + 0). Suppose the user has two displays side-by-side, both running at 1080p. + Suppose further that they've configured their OS to make the left display + their "primary" monitor, and that X-Plane is running in full-screen on + their right monitor only. In this case, the global desktop bounds would be + the rectangle from (1920, 0) to (3840, 1080). If the user later asked + X-Plane to draw on their primary monitor as well, the bounds would change + to (0, 0) to (3840, 1080). + + Finally, if the usable area of the virtual desktop is not a perfect + rectangle (for instance, because the monitors have different resolutions or + because one monitor is configured in the operating system to be above and + to the right of the other), the global desktop will include any wasted + space. Thus, if you have two 1080p monitors, and monitor 2 is configured to + have its bottom left touch monitor 1's upper right, your global desktop + area would be the rectangle from (0, 0) to (3840, 2160). + + Note that popped-out windows (windows drawn in their own operating system + windows, rather than "floating" within X-Plane) are not included in these + bounds. + } + PROCEDURE XPLMGetScreenBoundsGlobal( + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMReceiveMonitorBoundsGlobal_f + + This function is informed of the global bounds (in boxels) of a particular + monitor within the X-Plane global desktop space. Note that X-Plane must be + running in full screen on a monitor in order for that monitor to be passed + to you in this callback. + } +TYPE + XPLMReceiveMonitorBoundsGlobal_f = PROCEDURE( + inMonitorIndex : Integer; + inLeftBx : Integer; + inTopBx : Integer; + inRightBx : Integer; + inBottomBx : Integer; + inRefcon : pointer); cdecl; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMGetAllMonitorBoundsGlobal + + This routine immediately calls you back with the bounds (in boxels) of each + full-screen X-Plane window within the X-Plane global desktop space. Note + that if a monitor is *not* covered by an X-Plane window, you cannot get its + bounds this way. Likewise, monitors with only an X-Plane window (not in + full-screen mode) will not be included. + + If X-Plane is running in full-screen and your monitors are of the same size + and configured contiguously in the OS, then the combined global bounds of + all full-screen monitors will match the total global desktop bounds, as + returned by XPLMGetScreenBoundsGlobal(). (Of course, if X-Plane is running + in windowed mode, this will not be the case. Likewise, if you have + differently sized monitors, the global desktop space will include wasted + space.) + + Note that this function's monitor indices match those provided by + XPLMGetAllMonitorBoundsOS(), but the coordinates are different (since the + X-Plane global desktop may not match the operating system's global desktop, + and one X-Plane boxel may be larger than one pixel due to 150% or 200% + scaling). + } + PROCEDURE XPLMGetAllMonitorBoundsGlobal( + inMonitorBoundsCallback: XPLMReceiveMonitorBoundsGlobal_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMReceiveMonitorBoundsOS_f + + This function is informed of the global bounds (in pixels) of a particular + monitor within the operating system's global desktop space. Note that a + monitor index being passed to you here does not indicate that X-Plane is + running in full screen on this monitor, or even that any X-Plane windows + exist on this monitor. + } +TYPE + XPLMReceiveMonitorBoundsOS_f = PROCEDURE( + inMonitorIndex : Integer; + inLeftPx : Integer; + inTopPx : Integer; + inRightPx : Integer; + inBottomPx : Integer; + inRefcon : pointer); cdecl; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMGetAllMonitorBoundsOS + + This routine immediately calls you back with the bounds (in pixels) of each + monitor within the operating system's global desktop space. Note that + unlike XPLMGetAllMonitorBoundsGlobal(), this may include monitors that have + no X-Plane window on them. + + Note that this function's monitor indices match those provided by + XPLMGetAllMonitorBoundsGlobal(), but the coordinates are different (since + the X-Plane global desktop may not match the operating system's global + desktop, and one X-Plane boxel may be larger than one pixel). + } + PROCEDURE XPLMGetAllMonitorBoundsOS( + inMonitorBoundsCallback: XPLMReceiveMonitorBoundsOS_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetMouseLocation + + Deprecated in XPLM300. Modern windows should use + XPLMGetMouseLocationGlobal() instead. + + This routine returns the current mouse location in pixels relative to the + main X-Plane window. The bottom left corner of the main window is (0, 0). + Pass NULL to not receive info about either parameter. + + Because this function gives the mouse position relative to the main X-Plane + window (rather than in global bounds), this function should only be used by + legacy windows. Modern windows should instead get the mouse position in + global desktop coordinates using XPLMGetMouseLocationGlobal(). + + Note that unlike XPLMGetMouseLocationGlobal(), if the mouse goes outside + the user's main monitor (for instance, to a pop out window or a secondary + monitor), this function will not reflect it. + } + PROCEDURE XPLMGetMouseLocation( + outX : PInteger; { Can be nil } + outY : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetMouseLocationGlobal + + Returns the current mouse location in global desktop boxels. Unlike + XPLMGetMouseLocation(), the bottom left of the main X-Plane window is not + guaranteed to be (0, 0)---instead, the origin is the lower left of the + entire global desktop space. In addition, this routine gives the real mouse + location when the mouse goes to X-Plane windows other than the primary + display. Thus, it can be used with both pop-out windows and secondary + monitors. + + This is the mouse location function to use with modern windows (i.e., those + created by XPLMCreateWindowEx()). + + Pass NULL to not receive info about either parameter. + } + PROCEDURE XPLMGetMouseLocationGlobal( + outX : PInteger; { Can be nil } + outY : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetWindowGeometry + + This routine returns the position and size of a window. The units and + coordinate system vary depending on the type of window you have. + + If this is a legacy window (one compiled against a pre-XPLM300 version of + the SDK, or an XPLM300 window that was not created using + XPLMCreateWindowEx()), the units are pixels relative to the main X-Plane + display. + + If, on the other hand, this is a new X-Plane 11-style window (compiled + against the XPLM300 SDK and created using XPLMCreateWindowEx()), the units + are global desktop boxels. + + Pass NULL to not receive any paramter. + } + PROCEDURE XPLMGetWindowGeometry( + inWindowID : XPLMWindowID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetWindowGeometry + + This routine allows you to set the position and size of a window. + + The units and coordinate system match those of XPLMGetWindowGeometry(). + That is, modern windows use global desktop boxel coordinates, while legacy + windows use pixels relative to the main X-Plane display. + + Note that this only applies to "floating" windows (that is, windows that + are drawn within the X-Plane simulation windows, rather than being "popped + out" into their own first-class operating system windows). To set the + position of windows whose positioning mode is xplm_WindowPopOut, you'll + need to instead use XPLMSetWindowGeometryOS(). + } + PROCEDURE XPLMSetWindowGeometry( + inWindowID : XPLMWindowID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMGetWindowGeometryOS + + This routine returns the position and size of a "popped out" window (i.e., + a window whose positioning mode is xplm_WindowPopOut), in operating system + pixels. Pass NULL to not receive any parameter. + } + PROCEDURE XPLMGetWindowGeometryOS( + inWindowID : XPLMWindowID; + outLeft : PInteger; { Can be nil } + outTop : PInteger; { Can be nil } + outRight : PInteger; { Can be nil } + outBottom : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowGeometryOS + + This routine allows you to set the position and size, in operating system + pixel coordinates, of a popped out window (that is, a window whose + positioning mode is xplm_WindowPopOut, which exists outside the X-Plane + simulation window, in its own first-class operating system window). + + Note that you are responsible for ensuring both that your window is popped + out (using XPLMWindowIsPoppedOut()) and that a monitor really exists at the + OS coordinates you provide (using XPLMGetAllMonitorBoundsOS()). + } + PROCEDURE XPLMSetWindowGeometryOS( + inWindowID : XPLMWindowID; + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMGetWindowGeometryVR + + Returns the width and height, in boxels, of a window in VR. Note that you + are responsible for ensuring your window is in VR (using + XPLMWindowIsInVR()). + } + PROCEDURE XPLMGetWindowGeometryVR( + inWindowID : XPLMWindowID; + outWidthBoxels : PInteger; { Can be nil } + outHeightBoxels : PInteger); { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + +{$IFDEF XPLM301} + { + XPLMSetWindowGeometryVR + + This routine allows you to set the size, in boxels, of a window in VR (that + is, a window whose positioning mode is xplm_WindowVR). + + Note that you are responsible for ensuring your window is in VR (using + XPLMWindowIsInVR()). + } + PROCEDURE XPLMSetWindowGeometryVR( + inWindowID : XPLMWindowID; + widthBoxels : Integer; + heightBoxels : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + + { + XPLMGetWindowIsVisible + + Returns true (1) if the specified window is visible. + } + FUNCTION XPLMGetWindowIsVisible( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetWindowIsVisible + + This routine shows or hides a window. + } + PROCEDURE XPLMSetWindowIsVisible( + inWindowID : XPLMWindowID; + inIsVisible : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMWindowIsPoppedOut + + True if this window has been popped out (making it a first-class window in + the operating system), which in turn is true if and only if you have set + the window's positioning mode to xplm_WindowPopOut. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK cannot be popped out.) + } + FUNCTION XPLMWindowIsPoppedOut( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM301} + { + XPLMWindowIsInVR + + True if this window has been moved to the virtual reality (VR) headset, + which in turn is true if and only if you have set the window's positioning + mode to xplm_WindowVR. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM301 version of + the SDK cannot be moved to VR.) + } + FUNCTION XPLMWindowIsInVR( + inWindowID : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM301} + +{$IFDEF XPLM300} + { + XPLMSetWindowGravity + + A window's "gravity" controls how the window shifts as the whole X-Plane + window resizes. A gravity of 1 means the window maintains its positioning + relative to the right or top edges, 0 the left/bottom, and 0.5 keeps it + centered. + + Default gravity is (0, 1, 0, 1), meaning your window will maintain its + position relative to the top left and will not change size as its + containing window grows. + + If you wanted, say, a window that sticks to the top of the screen (with a + constant height), but which grows to take the full width of the window, you + would pass (0, 1, 1, 1). Because your left and right edges would maintain + their positioning relative to their respective edges of the screen, the + whole width of your window would change with the X-Plane window. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will simply get the default gravity.) + } + PROCEDURE XPLMSetWindowGravity( + inWindowID : XPLMWindowID; + inLeftGravity : Single; + inTopGravity : Single; + inRightGravity : Single; + inBottomGravity : Single); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowResizingLimits + + Sets the minimum and maximum size of the client rectangle of the given + window. (That is, it does not include any window styling that you might + have asked X-Plane to apply on your behalf.) All resizing operations are + constrained to these sizes. + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will have no minimum or maximum size.) + } + PROCEDURE XPLMSetWindowResizingLimits( + inWindowID : XPLMWindowID; + inMinWidthBoxels : Integer; + inMinHeightBoxels : Integer; + inMaxWidthBoxels : Integer; + inMaxHeightBoxels : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMWindowPositioningMode + + XPLMWindowPositionMode describes how X-Plane will position your window on + the user's screen. X-Plane will maintain this positioning mode even as the + user resizes their window or adds/removes full-screen monitors. + + Positioning mode can only be set for "modern" windows (that is, windows + created using XPLMCreateWindowEx() and compiled against the XPLM300 SDK). + Windows created using the deprecated XPLMCreateWindow(), or windows + compiled against a pre-XPLM300 version of the SDK will simply get the + "free" positioning mode. + } +TYPE + XPLMWindowPositioningMode = ( + { The default positioning mode. Set the window geometry and its future } + { position will be determined by its window gravity, resizing limits, and } + { user interactions. } + xplm_WindowPositionFree = 0 + + { Keep the window centered on the monitor you specify } + ,xplm_WindowCenterOnMonitor = 1 + + { Keep the window full screen on the monitor you specify } + ,xplm_WindowFullScreenOnMonitor = 2 + + { Like gui_window_full_screen_on_monitor, but stretches over *all* monitors } + { and popout windows. This is an obscure one... unless you have a very good } + { reason to need it, you probably don't! } + ,xplm_WindowFullScreenOnAllMonitors = 3 + + { A first-class window in the operating system, completely separate from the } + { X-Plane window(s) } + ,xplm_WindowPopOut = 4 + +{$IFDEF XPLM301} + { A floating window visible on the VR headset } + ,xplm_WindowVR = 5 +{$ENDIF XPLM301} + + ); + PXPLMWindowPositioningMode = ^XPLMWindowPositioningMode; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowPositioningMode + + Sets the policy for how X-Plane will position your window. + + Some positioning modes apply to a particular monitor. For those modes, you + can pass a negative monitor index to position the window on the main + X-Plane monitor (the screen with the X-Plane menu bar at the top). Or, if + you have a specific monitor you want to position your window on, you can + pass a real monitor index as received from, e.g., + XPLMGetAllMonitorBoundsOS(). + + Only applies to modern windows. (Windows created using the deprecated + XPLMCreateWindow(), or windows compiled against a pre-XPLM300 version of + the SDK will always use xplm_WindowPositionFree.) + } + PROCEDURE XPLMSetWindowPositioningMode( + inWindowID : XPLMWindowID; + inPositioningMode : XPLMWindowPositioningMode; + inMonitorIndex : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + +{$IFDEF XPLM300} + { + XPLMSetWindowTitle + + Sets the name for a window. This only applies to windows that opted-in to + styling as an X-Plane 11 floating window (i.e., with styling mode + xplm_WindowDecorationRoundRectangle) when they were created using + XPLMCreateWindowEx(). + } + PROCEDURE XPLMSetWindowTitle( + inWindowID : XPLMWindowID; + inWindowTitle : XPLMString); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMGetWindowRefCon + + Returns a window's reference constant, the unique value you can use for + your own purposes. + } + FUNCTION XPLMGetWindowRefCon( + inWindowID : XPLMWindowID) : pointer; + cdecl; external XPLM_DLL; + + { + XPLMSetWindowRefCon + + Sets a window's reference constant. Use this to pass data to yourself in + the callbacks. + } + PROCEDURE XPLMSetWindowRefCon( + inWindowID : XPLMWindowID; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMTakeKeyboardFocus + + This routine gives a specific window keyboard focus. Keystrokes will be + sent to that window. Pass a window ID of 0 to remove keyboard focus from + any plugin-created windows and instead pass keyboard strokes directly to + X-Plane. + } + PROCEDURE XPLMTakeKeyboardFocus( + inWindow : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMHasKeyboardFocus + + Returns true (1) if the indicated window has keyboard focus. Pass a window + ID of 0 to see if no plugin window has focus, and all keystrokes will go + directly to X-Plane. + } + FUNCTION XPLMHasKeyboardFocus( + inWindow : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMBringWindowToFront + + This routine brings the window to the front of the Z-order for its layer. + Windows are brought to the front automatically when they are created. + Beyond that, you should make sure you are front before handling mouse + clicks. + + Note that this only brings your window to the front of its layer + (XPLMWindowLayer). Thus, if you have a window in the floating window layer + (xplm_WindowLayerFloatingWindows), but there is a modal window (in layer + xplm_WindowLayerModal) above you, you would still not be the true frontmost + window after calling this. (After all, the window layers are strictly + ordered, and no window in a lower layer can ever be above any window in a + higher one.) + } + PROCEDURE XPLMBringWindowToFront( + inWindow : XPLMWindowID); + cdecl; external XPLM_DLL; + + { + XPLMIsWindowInFront + + This routine returns true if the window you passed in is the frontmost + visible window in its layer (XPLMWindowLayer). + + Thus, if you have a window at the front of the floating window layer + (xplm_WindowLayerFloatingWindows), this will return true even if there is a + modal window (in layer xplm_WindowLayerModal) above you. (Not to worry, + though: in such a case, X-Plane will not pass clicks or keyboard input down + to your layer until the window above stops "eating" the input.) + + Note that legacy windows are always placed in layer + xplm_WindowLayerFlightOverlay, while modern-style windows default to + xplm_WindowLayerFloatingWindows. This means it's perfectly consistent to + have two different plugin-created windows (one legacy, one modern) *both* + be in the front (of their different layers!) at the same time. + } + FUNCTION XPLMIsWindowInFront( + inWindow : XPLMWindowID) : Integer; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * KEY SNIFFERS + ___________________________________________________________________________} +{ + Low-level keyboard handlers. Allows for intercepting keystrokes outside the + normal rules of the user interface. +} + + + { + XPLMKeySniffer_f + + This is the prototype for a low level key-sniffing function. Window-based + UI _should not use this_! The windowing system provides high-level + mediated keyboard access, via the callbacks you attach to your + XPLMCreateWindow_t. By comparison, the key sniffer provides low level + keyboard access. + + Key sniffers are provided to allow libraries to provide non-windowed user + interaction. For example, the MUI library uses a key sniffer to do pop-up + text entry. + + Return 1 to pass the key on to the next sniffer, the window manager, + X-Plane, or whomever is down stream. Return 0 to consume the key. + + Warning: this API declares virtual keys as a signed character; however the + VKEY #define macros in XPLMDefs.h define the vkeys using unsigned values + (that is 0x80 instead of -0x80). So you may need to cast the incoming vkey + to an unsigned char to get correct comparisons in C. + } +TYPE + XPLMKeySniffer_f = FUNCTION( + inChar : XPLMChar; + inFlags : XPLMKeyFlags; + inVirtualKey : XPLMChar; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMRegisterKeySniffer + + This routine registers a key sniffing callback. You specify whether you + want to sniff before the window system, or only sniff keys the window + system does not consume. You should ALMOST ALWAYS sniff non-control keys + after the window system. When the window system consumes a key, it is + because the user has "focused" a window. Consuming the key or taking + action based on the key will produce very weird results. Returns + 1 if successful. + } + FUNCTION XPLMRegisterKeySniffer( + inCallback : XPLMKeySniffer_f; + inBeforeWindows : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterKeySniffer + + This routine unregisters a key sniffer. You must unregister a key sniffer + for every time you register one with the exact same signature. Returns 1 + if successful. + } + FUNCTION XPLMUnregisterKeySniffer( + inCallback : XPLMKeySniffer_f; + inBeforeWindows : Integer; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * HOT KEYS + ___________________________________________________________________________} +{ + Keystrokes that can be managed by others. These are lower-level than window + keyboard handlers (i.e., callbacks you attach to your XPLMCreateWindow_t), + but higher level than key sniffers. +} + + + { + XPLMHotKey_f + + Your hot key callback simply takes a pointer of your choosing. + } +TYPE + XPLMHotKey_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMHotKeyID + + An opaque ID used to identify a hot key. + } + XPLMHotKeyID = pointer; + PXPLMHotKeyID = ^XPLMHotKeyID; + + { + XPLMRegisterHotKey + + This routine registers a hot key. You specify your preferred key stroke + virtual key/flag combination, a description of what your callback does (so + other plug-ins can describe the plug-in to the user for remapping) and a + callback function and opaque pointer to pass in). A new hot key ID is + returned. During execution, the actual key associated with your hot key + may change, but you are insulated from this. + } + FUNCTION XPLMRegisterHotKey( + inVirtualKey : XPLMChar; + inFlags : XPLMKeyFlags; + inDescription : XPLMString; + inCallback : XPLMHotKey_f; + inRefcon : pointer) : XPLMHotKeyID; + cdecl; external XPLM_DLL; + + { + XPLMUnregisterHotKey + + Unregisters a hot key. You can only unregister your own hot keys. + } + PROCEDURE XPLMUnregisterHotKey( + inHotKey : XPLMHotKeyID); + cdecl; external XPLM_DLL; + + { + XPLMCountHotKeys + + Returns the number of current hot keys. + } + FUNCTION XPLMCountHotKeys: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetNthHotKey + + Returns a hot key by index, for iteration on all hot keys. + } + FUNCTION XPLMGetNthHotKey( + inIndex : Integer) : XPLMHotKeyID; + cdecl; external XPLM_DLL; + + { + XPLMGetHotKeyInfo + + Returns information about the hot key. Return NULL for any parameter you + don't want info about. The description should be at least 512 chars long. + } + PROCEDURE XPLMGetHotKeyInfo( + inHotKey : XPLMHotKeyID; + outVirtualKey : XPLMString; { Can be nil } + outFlags : PXPLMKeyFlags; { Can be nil } + outDescription : XPLMString; { Can be nil } + outPlugin : PXPLMPluginID); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetHotKeyCombination + + Remaps a hot key's keystrokes. You may remap another plugin's keystrokes. + } + PROCEDURE XPLMSetHotKeyCombination( + inHotKey : XPLMHotKeyID; + inVirtualKey : XPLMChar; + inFlags : XPLMKeyFlags); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMGraphics.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMGraphics.pas new file mode 100644 index 0000000..20ff61a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMGraphics.pas @@ -0,0 +1,424 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMGraphics; +INTERFACE +{ + A few notes on coordinate systems: + + X-Plane uses three kinds of coordinates. Global coordinates are specified + as latitude, longitude and elevation. This coordinate system never changes + but is not very precise. + + OpenGL (or 'local') coordinates are cartesian and shift with the plane. + They offer more precision and are used for 3-d OpenGL drawing. The X axis + is aligned east-west with positive X meaning east. The Y axis is aligned + straight up and down at the point 0,0,0 (but since the earth is round it is + not truly straight up and down at other points). The Z axis is aligned + north-south at 0, 0, 0 with positive Z pointing south (but since the earth + is round it isn't exactly north-south as you move east or west of 0, 0, 0). + One unit is one meter and the point 0,0,0 is on the surface of the earth at + sea level for some latitude and longitude picked by the sim such that the + user's aircraft is reasonably nearby. + + 2-d Panel coordinates are 2d, with the X axis horizontal and the Y axis + vertical. The point 0,0 is the bottom left and 1024,768 is the upper + right of the screen. This is true no matter what resolution the user's + monitor is in; when running in higher resolution, graphics will be + scaled. + + Use X-Plane's routines to convert between global and local coordinates. Do + not attempt to do this conversion yourself; the precise 'roundness' of + X-Plane's physics model may not match your own, and (to make things + weirder) the user can potentially customize the physics of the current + planet. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * X-PLANE GRAPHICS + ___________________________________________________________________________} +{ + These routines allow you to use OpenGL with X-Plane. +} + + + { + XPLMTextureID + + XPLM Texture IDs name well-known textures in the sim for you to use. This + allows you to recycle textures from X-Plane, saving VRAM. + + *Warning*: do not use these enums. The only remaining use they have is to + access the legacy compatibility v10 UI texture; if you need this, get it + via the Widgets library. + } +TYPE + XPLMTextureID = ( + { The bitmap that contains window outlines, button outlines, fonts, etc. } + xplm_Tex_GeneralInterface = 0 + +{$IFDEF XPLM_DEPRECATED} + { The exterior paint for the user's aircraft (daytime). } + ,xplm_Tex_AircraftPaint = 1 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { The exterior light map for the user's aircraft. } + ,xplm_Tex_AircraftLiteMap = 2 +{$ENDIF XPLM_DEPRECATED} + + ); + PXPLMTextureID = ^XPLMTextureID; + + { + XPLMSetGraphicsState + + XPLMSetGraphicsState changes OpenGL's fixed function pipeline state. You + are not responsible for restoring any state that is accessed via + XPLMSetGraphicsState, but you are responsible for not accessing this state + directly. + + - inEnableFog - enables or disables fog, equivalent to: glEnable(GL_FOG); + - inNumberTexUnits - enables or disables a number of multitexturing units. + If the number is 0, 2d texturing is disabled entirely, as in + glDisable(GL_TEXTURE_2D); Otherwise, 2d texturing is enabled, and a + number of multitexturing units are enabled sequentially, starting with + unit 0, e.g. glActiveTextureARB(GL_TEXTURE0_ARB); glEnable + (GL_TEXTURE_2D); + - inEnableLighting - enables or disables OpenGL lighting, e.g. + glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); + - inEnableAlphaTesting - enables or disables the alpha test per pixel, e.g. + glEnable(GL_ALPHA_TEST); + - inEnableAlphaBlending - enables or disables alpha blending per pixel, + e.g. glEnable(GL_BLEND); + - inEnableDepthTesting - enables per pixel depth testing, as in + glEnable(GL_DEPTH_TEST); + - inEnableDepthWriting - enables writing back of depth information to the + depth bufffer, as in glDepthMask(GL_TRUE); + + The purpose of this function is to change OpenGL state while keeping + X-Plane aware of the state changes; this keeps X-Plane from getting + surprised by OGL state changes, and prevents X-Plane and plug-ins from + having to set all state before all draws; XPLMSetGraphicsState internally + skips calls to change state that is already properly enabled. + + X-Plane does not have a 'default' OGL state for plug-ins with respect to + the above state vector; plug-ins should totally set OGL state using this + API before drawing. Use XPLMSetGraphicsState instead of any of the above + OpenGL calls. + + WARNING: Any routine that performs drawing (e.g. XPLMDrawString or widget + code) may change X-Plane's state. Always set state before drawing after + unknown code has executed. + + *Deprecation Warnings*: X-Plane's lighting and fog environemnt is + significantly more complex than the fixed function pipeline can express; + do not assume that lighting and fog state is a good approximation for 3-d + drawing. Prefer to use XPLMInstancing to draw objects. All calls to + XPLMSetGraphicsState should have no fog or lighting. + } + PROCEDURE XPLMSetGraphicsState( + inEnableFog : Integer; + inNumberTexUnits : Integer; + inEnableLighting : Integer; + inEnableAlphaTesting: Integer; + inEnableAlphaBlending: Integer; + inEnableDepthTesting: Integer; + inEnableDepthWriting: Integer); + cdecl; external XPLM_DLL; + + { + XPLMBindTexture2d + + XPLMBindTexture2d changes what texture is bound to the 2d texturing + target. This routine caches the current 2d texture across all texturing + units in the sim and plug-ins, preventing extraneous binding. For + example, consider several plug-ins running in series; if they all use the + 'general interface' bitmap to do UI, calling this function will skip the + rebinding of the general interface texture on all but the first plug-in, + which can provide better frame rate son some graphics cards. + + inTextureID is the ID of the texture object to bind; inTextureUnit is a + zero-based texture unit (e.g. 0 for the first one), up to a maximum of 4 + units. (This number may increase in future versions of X-Plane.) + + Use this routine instead of glBindTexture(GL_TEXTURE_2D, ....); + } + PROCEDURE XPLMBindTexture2d( + inTextureNum : Integer; + inTextureUnit : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGenerateTextureNumbers + + Use this routine instead of glGenTextures to generate new texture object + IDs. This routine historically ensured that plugins don't use texure IDs + that X-Plane is reserving for its own use. + } + PROCEDURE XPLMGenerateTextureNumbers( + outTextureIDs : PInteger; + inCount : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM_DEPRECATED} + { + XPLMGetTexture + + XPLMGetTexture returns the OpenGL texture ID of an X-Plane texture based on + a generic identifying code. For example, you can get the texture for + X-Plane's UI bitmaps. + } + FUNCTION XPLMGetTexture( + inTexture : XPLMTextureID) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + { + XPLMWorldToLocal + + This routine translates coordinates from latitude, longitude, and altitude + to local scene coordinates. Latitude and longitude are in decimal degrees, + and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + meters in the local OpenGL coordinate system. + } + PROCEDURE XPLMWorldToLocal( + inLatitude : Real; + inLongitude : Real; + inAltitude : Real; + outX : PReal; + outY : PReal; + outZ : PReal); + cdecl; external XPLM_DLL; + + { + XPLMLocalToWorld + + This routine translates a local coordinate triplet back into latitude, + longitude, and altitude. Latitude and longitude are in decimal degrees, + and altitude is in meters MSL (mean sea level). The XYZ coordinates are in + meters in the local OpenGL coordinate system. + + NOTE: world coordinates are less precise than local coordinates; you should + try to avoid round tripping from local to world and back. + } + PROCEDURE XPLMLocalToWorld( + inX : Real; + inY : Real; + inZ : Real; + outLatitude : PReal; + outLongitude : PReal; + outAltitude : PReal); + cdecl; external XPLM_DLL; + + { + XPLMDrawTranslucentDarkBox + + This routine draws a translucent dark box, partially obscuring parts of the + screen but making text easy to read. This is the same graphics primitive + used by X-Plane to show text files and ATC info. + } + PROCEDURE XPLMDrawTranslucentDarkBox( + inLeft : Integer; + inTop : Integer; + inRight : Integer; + inBottom : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * X-PLANE TEXT + ___________________________________________________________________________} + + { + XPLMFontID + + X-Plane features some fixed-character fonts. Each font may have its own + metrics. + + WARNING: Some of these fonts are no longer supported or may have changed + geometries. For maximum copmatibility, see the comments below. + + Note: X-Plane 7 supports proportional-spaced fonts. Since no measuring + routine is available yet, the SDK will normally draw using a fixed-width + font. You can use a dataref to enable proportional font drawing on XP7 if + you want to. + } +TYPE + XPLMFontID = ( + { Mono-spaced font for user interface. Available in all versions of the SDK.} + xplmFont_Basic = 0 + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Menus = 1 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Metal = 2 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Led = 3 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_LedWide = 4 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelHUD = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelEFIS = 6 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_PanelGPS = 7 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosGA = 8 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosBC = 9 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosHM = 10 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosGANarrow = 11 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosBCNarrow = 12 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_RadiosHMNarrow = 13 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Timer = 14 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_FullRound = 15 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_SmallRound = 16 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { Deprecated, do not use. } + ,xplmFont_Menus_Localized = 17 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM200} + { Proportional UI font. } + ,xplmFont_Proportional = 18 +{$ENDIF XPLM200} + + ); + PXPLMFontID = ^XPLMFontID; + + { + XPLMDrawString + + This routine draws a NULL termianted string in a given font. Pass in the + lower left pixel that the character is to be drawn onto. Also pass the + character and font ID. This function returns the x offset plus the width of + all drawn characters. The color to draw in is specified as a pointer to an + array of three floating point colors, representing RGB intensities from 0.0 + to 1.0. + } + PROCEDURE XPLMDrawString( + inColorRGB : PSingle; + inXOffset : Integer; + inYOffset : Integer; + inChar : XPLMString; + inWordWrapWidth : PInteger; { Can be nil } + inFontID : XPLMFontID); + cdecl; external XPLM_DLL; + + { + XPLMDrawNumber + + This routine draws a number similar to the digit editing fields in + PlaneMaker and data output display in X-Plane. Pass in a color, a + position, a floating point value, and formatting info. Specify how many + integer and how many decimal digits to show and whether to show a sign, as + well as a character set. This routine returns the xOffset plus width of the + string drawn. + } + PROCEDURE XPLMDrawNumber( + inColorRGB : PSingle; + inXOffset : Integer; + inYOffset : Integer; + inValue : Real; + inDigits : Integer; + inDecimals : Integer; + inShowSign : Integer; + inFontID : XPLMFontID); + cdecl; external XPLM_DLL; + + { + XPLMGetFontDimensions + + This routine returns the width and height of a character in a given font. + It also tells you if the font only supports numeric digits. Pass NULL if + you don't need a given field. Note that for a proportional font the width + will be an arbitrary, hopefully average width. + } + PROCEDURE XPLMGetFontDimensions( + inFontID : XPLMFontID; + outCharWidth : PInteger; { Can be nil } + outCharHeight : PInteger; { Can be nil } + outDigitsOnly : PInteger); { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMMeasureString + + This routine returns the width in pixels of a string using a given font. + The string is passed as a pointer plus length (and does not need to be null + terminated); this is used to allow for measuring substrings. The return + value is floating point; it is possible that future font drawing may allow + for fractional pixels. + } + FUNCTION XPLMMeasureString( + inFontID : XPLMFontID; + inChar : XPLMString; + inNumChars : Integer) : Single; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMInstance.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMInstance.pas new file mode 100644 index 0000000..a38d2bb --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMInstance.pas @@ -0,0 +1,125 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMInstance; +INTERFACE +{ + This API provides instanced drawing of X-Plane objects (.obj files). In + contrast to old drawing APIs, which required you to draw your own objects + per-frame, the instancing API allows you to simply register an OBJ for + drawing, then move or manipulate it later (as needed). + + This provides one tremendous benefit: it keeps all dataref operations for + your object in one place. Because datarefs are main thread only, allowing + dataref access anywhere is a serious performance bottleneck for the + simulator---the whole simulator has to pause and wait for each dataref + access. This performance penalty will only grow worse as X-Plane moves + toward an ever more heavily multithreaded engine. + + The instancing API allows X-Plane to isolate all dataref manipulations for + all plugin object drawing to one place, potentially providing huge + performance gains. + + Here's how it works: + + When an instance is created, it provides a list of all datarefs you want to + manipulate in for the OBJ in the future. This list of datarefs replaces the + ad-hoc collections of dataref objects previously used by art assets. Then, + per-frame, you can manipulate the instance by passing in a "block" of + packed floats representing the current values of the datarefs for your + instance. (Note that the ordering of this set of packed floats must exactly + match the ordering of the datarefs when you created your instance.) +} + +USES + XPLMDefs, XPLMScenery; + {$A4} +{___________________________________________________________________________ + * Instance Creation and Destruction + ___________________________________________________________________________} +{ + Registers and unregisters instances. +} + + +TYPE + { + XPLMInstanceRef + + An opaque handle to an instance. + } + XPLMInstanceRef = pointer; + PXPLMInstanceRef = ^XPLMInstanceRef; + + { + XPLMCreateInstance + + XPLMCreateInstance creates a new instance, managed by your plug-in, and + returns a handle to the instance. A few important requirements: + + * The object passed in must be fully loaded and returned from the XPLM + before you can create your instance; you cannot pass a null obj ref, nor + can you change the ref later. + + * If you use any custom datarefs in your object, they must be registered + before the object is loaded. This is true even if their data will be + provided via the instance dataref list. + + * The instance dataref array must be a valid ptr to an array of at least + one item that is null terminated. That is, if you do not want any + datarefs, you must passa ptr to an array with a null item. You cannot + pass null for this. + } + FUNCTION XPLMCreateInstance( + obj : XPLMObjectRef; + datarefs : PXPLMString) : XPLMInstanceRef; + cdecl; external XPLM_DLL; + + { + XPLMDestroyInstance + + XPLMDestroyInstance destroys and deallocates your instance; once called, + you are still responsible for releasing the OBJ ref. + + Tip: you can release your OBJ ref after you call XPLMCreateInstance as long + as you never use it again; the instance will maintain its own reference to + the OBJ and the object OBJ be deallocated when the instance is destroyed. + } + PROCEDURE XPLMDestroyInstance( + instance : XPLMInstanceRef); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * Instance Manipulation + ___________________________________________________________________________} + + { + XPLMInstanceSetPosition + + Updates both the position of the instance and all datarefs you registered + for it. Call this from a flight loop callback or UI callback. + + __DO NOT__ call XPLMInstanceSetPosition from a drawing callback; the whole + point of instancing is that you do not need any drawing callbacks. Setting + instance data from a drawing callback may have undefined consequences, and + the drawing callback hurts FPS unnecessarily. + + The memory pointed to by the data pointer must be large enough to hold one + float for every data ref you have registered, and must contain valid + floating point data. + + BUG: before X-Plane 11.50, if you have no dataref registered, you must + still pass a valid pointer for data and not null. + } + PROCEDURE XPLMInstanceSetPosition( + instance : XPLMInstanceRef; + new_position : PXPLMDrawInfo_t; + data : PSingle); + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMMap.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMMap.pas new file mode 100644 index 0000000..ea00ee0 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMMap.pas @@ -0,0 +1,608 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMMap; +INTERFACE +{ + This API allows you to create new layers within X-Plane maps. Your layers + can draw arbitrary OpenGL, but they conveniently also have access to + X-Plane's built-in icon and label drawing functions. + + As of X-Plane 11, map drawing happens in three stages: + + 1. backgrounds and "fill," + 2. icons, and + 3. labels. + + Thus, all background drawing gets layered beneath all icons, which likewise + get layered beneath all labels. Within each stage, the map obeys a + consistent layer ordering, such that "fill" layers (layers that cover a + large amount of map area, like the terrain and clouds) appear beneath + "markings" layers (like airport icons). This ensures that layers with fine + details don't get obscured by layers with larger details. + + The XPLM map API reflects both aspects of this draw layering: you can + register a layer as providing either markings or fill, and X-Plane will + draw your fill layers beneath your markings layers (regardless of + registration order). Likewise, you are guaranteed that your layer's icons + (added from within an icon callback) will go above your layer's OpenGL + drawing, and your labels will go above your icons. + + The XPLM guarantees that all plugin-created fill layers go on top of all + native X-Plane fill layers, and all plugin-created markings layers go on + top of all X-Plane markings layers (with the exception of the aircraft + icons). It also guarantees that the draw order of your own plugin's layers + will be consistent. But, for layers created by different plugins, the only + guarantee is that we will draw all of one plugin's layers of each type + (fill, then markings), then all of the others'; we don't guarantee which + plugin's fill and markings layers go on top of the other's. + + As of X-Plane 11, maps use true cartographic projections for their drawing, + and different maps may use different projections. For that reason, all + drawing calls include an opaque handle for the projection you should use to + do the drawing. Any time you would draw at a particular latitude/longitude, + you'll need to ask the projection to translate that position into "map + coordinates." (Note that the projection is guaranteed not to change between + calls to your prepare-cache hook, so if you cache your map coordinates + ahead of time, there's no need to re-project them when you actually draw.) + + In addition to mapping normal latitude/longitude locations into map + coordinates, the projection APIs also let you know the current heading for + north. (Since X-Plane 11 maps can rotate to match the heading of the user's + aircraft, it's not safe to assume that north is at zero degrees rotation.) +} + +USES + XPLMDefs; + {$A4} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * DRAWING CALLBACKS + ___________________________________________________________________________} +{ + When you create a new map layer (using XPLMCreateMapLayer), you can provide + any or all of these callbacks. They allow you to insert your own OpenGL + drawing, text labels, and icons into the X-Plane map at the appropriate + places, allowing your layer to behave as similarly to X-Plane's built-in + layers as possible. +} + + +TYPE + { + XPLMMapLayerID + + This is an opaque handle for a plugin-created map layer. Pass it to the map + drawing APIs from an appropriate callback to draw in the layer you created. + } + XPLMMapLayerID = pointer; + PXPLMMapLayerID = ^XPLMMapLayerID; + + { + XPLMMapProjectionID + + This is an opaque handle for a map projection. Pass it to the projection + APIs to translate between map coordinates and latitude/longitudes. + } + XPLMMapProjectionID = pointer; + PXPLMMapProjectionID = ^XPLMMapProjectionID; + + { + XPLMMapStyle + + Indicates the visual style being drawn by the map. In X-Plane, the user can + choose between a number of map types, and different map types may have use + a different visual representation for the same elements (for instance, the + visual style of the terrain layer changes drastically between the VFR and + IFR layers), or certain layers may be disabled entirely in some map types + (e.g., localizers are only visible in the IFR low-enroute style). + } + XPLMMapStyle = ( + xplm_MapStyle_VFR_Sectional = 0 + + ,xplm_MapStyle_IFR_LowEnroute = 1 + + ,xplm_MapStyle_IFR_HighEnroute = 2 + + ); + PXPLMMapStyle = ^XPLMMapStyle; + + { + XPLMMapDrawingCallback_f + + This is the OpenGL map drawing callback for plugin-created map layers. You + can perform arbitrary OpenGL drawing from this callback, with one + exception: changes to the Z-buffer are not permitted, and will result in + map drawing errors. + + All drawing done from within this callback appears beneath all built-in + X-Plane icons and labels, but above the built-in "fill" layers (layers + providing major details, like terrain and water). Note, however, that the + relative ordering between the drawing callbacks of different plugins is not + guaranteed. + } + XPLMMapDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapIconDrawingCallback_f + + This is the icon drawing callback that enables plugin-created map layers to + draw icons using X-Plane's built-in icon drawing functionality. You can + request an arbitrary number of PNG icons to be drawn via + XPLMDrawMapIconFromSheet() from within this callback, but you may not + perform any OpenGL drawing here. + + Icons enqueued by this function will appear above all OpenGL drawing + (performed by your optional XPLMMapDrawingCallback_f), and above all + built-in X-Plane map icons of the same layer type ("fill" or "markings," as + determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + however, that the relative ordering between the drawing callbacks of + different plugins is not guaranteed. + } + XPLMMapIconDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapLabelDrawingCallback_f + + This is the label drawing callback that enables plugin-created map layers + to draw text labels using X-Plane's built-in labeling functionality. You + can request an arbitrary number of text labels to be drawn via + XPLMDrawMapLabel() from within this callback, but you may not perform any + OpenGL drawing here. + + Labels enqueued by this function will appear above all OpenGL drawing + (performed by your optional XPLMMapDrawingCallback_f), and above all + built-in map icons and labels of the same layer type ("fill" or "markings," + as determined by the XPLMMapLayerType in your XPLMCreateMapLayer_t). Note, + however, that the relative ordering between the drawing callbacks of + different plugins is not guaranteed. + } + XPLMMapLabelDrawingCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inMapBoundsLeftTopRightBottom: PSingle; + zoomRatio : Single; + mapUnitsPerUserInterfaceUnit: Single; + mapStyle : XPLMMapStyle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * LAYER MANAGEMENT CALLBACKS + ___________________________________________________________________________} +{ + These are various "bookkeeping" callbacks that your map layer can receive + (if you provide the callback in your XPLMCreateMapLayer_t). They allow you + to manage the lifecycle of your layer, as well as cache any + computationally-intensive preparation you might need for drawing. +} + + + { + XPLMMapPrepareCacheCallback_f + + A callback used to allow you to cache whatever information your layer needs + to draw in the current map area. + + This is called each time the map's total bounds change. This is typically + triggered by new DSFs being loaded, such that X-Plane discards old, + now-distant DSFs and pulls in new ones. At that point, the available bounds + of the map also change to match the new DSF area. + + By caching just the information you need to draw in this area, your future + draw calls can be made faster, since you'll be able to simply "splat" your + precomputed information each frame. + + We guarantee that the map projection will not change between successive + prepare cache calls, nor will any draw call give you bounds outside these + total map bounds. So, if you cache the projected map coordinates of all the + items you might want to draw in the total map area, you can be guaranteed + that no draw call will be asked to do any new work. + } +TYPE + XPLMMapPrepareCacheCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inTotalMapBoundsLeftTopRightBottom: PSingle; + projection : XPLMMapProjectionID; + inRefcon : pointer); cdecl; + + { + XPLMMapWillBeDeletedCallback_f + + Called just before your map layer gets deleted. Because SDK-created map + layers have the same lifetime as the X-Plane map that contains them, if the + map gets unloaded from memory, your layer will too. + } + XPLMMapWillBeDeletedCallback_f = PROCEDURE( + inLayer : XPLMMapLayerID; + inRefcon : pointer); cdecl; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP LAYER CREATION AND DESTRUCTION + ___________________________________________________________________________} +{ + Enables the creation of new map layers. Layers are created for a particular + instance of the X-Plane map. For instance, if you want your layer to appear + in both the normal map interface and the Instructor Operator Station (IOS), + you would need two separate calls to XPLMCreateMapLayer(), with two + different values for your XPLMCreateMapLayer_t::layer_name. + + Your layer's lifetime will be determined by the lifetime of the map it is + created in. If the map is destroyed (on the X-Plane side), your layer will + be too, and you'll receive a callback to your + XPLMMapWillBeDeletedCallback_f. +} + + + { + XPLMMapLayerType + + Indicates the type of map layer you are creating. Fill layers will always + be drawn beneath markings layers. + } +TYPE + XPLMMapLayerType = ( + { A layer that draws "fill" graphics, like weather patterns, terrain, etc. } + { Fill layers frequently cover a large portion of the visible map area. } + xplm_MapLayer_Fill = 0 + + { A layer that provides markings for particular map features, like NAVAIDs, } + { airports, etc. Even dense markings layers cover a small portion of the } + { total map area. } + ,xplm_MapLayer_Markings = 1 + + ); + PXPLMMapLayerType = ^XPLMMapLayerType; + +CONST + { Globally unique identifier for X-Plane's Map window, used as the } + { mapToCreateLayerIn parameter in XPLMCreateMapLayer_t } + XPLM_MAP_USER_INTERFACE = "XPLM_MAP_USER_INTERFACE"; + + { Globally unique identifier for X-Plane's Instructor Operator Station } + { window, used as the mapToCreateLayerIn parameter in XPLMCreateMapLayer_t } + XPLM_MAP_IOS = "XPLM_MAP_IOS"; + + { + XPLMCreateMapLayer_t + + This structure defines all of the parameters used to create a map layer + using XPLMCreateMapLayer. The structure will be expanded in future SDK APIs + to include more features. Always set the structSize member to the size of + your struct in bytes! + + Each layer must be associated with exactly one map instance in X-Plane. + That map, and that map alone, will call your callbacks. Likewise, when that + map is deleted, your layer will be as well. + } +TYPE + XPLMCreateMapLayer_t = RECORD + { Used to inform XPLMCreateMapLayer() of the SDK version you compiled } + { against; should always be set to sizeof(XPLMCreateMapLayer_t) } + structSize : Integer; + { Globally unique string identifying the map you want this layer to appear } + { in. As of XPLM300, this is limited to one of XPLM_MAP_USER_INTERFACE or } + { XPLM_MAP_IOS } + mapToCreateLayerIn : XPLMString; + { The type of layer you are creating, used to determine draw order (all } + { plugin-created markings layers are drawn above all plugin-created fill } + { layers) } + layerType : XPLMMapLayerType; + { Optional callback to inform you this layer is being deleted (due to its } + { owning map being destroyed) } + willBeDeletedCallback : XPLMMapWillBeDeletedCallback_f; + { Optional callback you want to use to prepare your draw cache when the map } + { bounds change (set to NULL if you don't want this callback) } + prepCacheCallback : XPLMMapPrepareCacheCallback_f; + { Optional callback you want to use for arbitrary OpenGL drawing, which goes } + { beneath all icons in the map's layering system (set to NULL if you don't } + { want this callback) } + drawCallback : XPLMMapDrawingCallback_f; + { Optional callback you want to use for drawing icons, which go above all } + { built-in X-Plane icons (except the aircraft) in the map's layering system } + { (set to NULL if you don't want this callback) } + iconCallback : XPLMMapIconDrawingCallback_f; + { Optional callback you want to use for drawing map labels, which go above } + { all built-in X-Plane icons and labels (except those of aircraft) in the } + { map's layering system (set to NULL if you don't want this callback) } + labelCallback : XPLMMapLabelDrawingCallback_f; + { True if you want a checkbox to be created in the map UI to toggle this } + { layer on and off; false if the layer should simply always be enabled } + showUiToggle : Integer; + { Short label to use for this layer in the user interface } + layerName : XPLMString; + { A reference to arbitrary data that will be passed to your callbacks } + refcon : pointer; + END; + PXPLMCreateMapLayer_t = ^XPLMCreateMapLayer_t; + + { + XPLMCreateMapLayer + + This routine creates a new map layer. You pass in an XPLMCreateMapLayer_t + structure with all of the fields set in. You must set the structSize of + the structure to the size of the actual structure you used. + + Returns NULL if the layer creation failed. This happens most frequently + because the map you specified in your + XPLMCreateMapLayer_t::mapToCreateLayerIn field doesn't exist (that is, if + XPLMMapExists() returns 0 for the specified map). You can use + XPLMRegisterMapCreationHook() to get a notification each time a new map is + opened in X-Plane, at which time you can create layers in it. + } + FUNCTION XPLMCreateMapLayer( + inParams : PXPLMCreateMapLayer_t) : XPLMMapLayerID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyMapLayer + + Destroys a map layer you created (calling your + XPLMMapWillBeDeletedCallback_f if applicable). Returns true if a deletion + took place. + } + FUNCTION XPLMDestroyMapLayer( + inLayer : XPLMMapLayerID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMMapCreatedCallback_f + + A callback to notify your plugin that a new map has been created in + X-Plane. This is the best time to add a custom map layer using + XPLMCreateMapLayer(). + + No OpenGL drawing is permitted within this callback. + } +TYPE + XPLMMapCreatedCallback_f = PROCEDURE( + mapIdentifier : XPLMString; + refcon : pointer); cdecl; + + { + XPLMRegisterMapCreationHook + + Registers your callback to receive a notification each time a new map is + constructed in X-Plane. This callback is the best time to add your custom + map layer using XPLMCreateMapLayer(). + + Note that you will not be notified about any maps that already exist---you + can use XPLMMapExists() to check for maps that were created previously. + } + PROCEDURE XPLMRegisterMapCreationHook( + callback : XPLMMapCreatedCallback_f; + refcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMMapExists + + Returns 1 if the map with the specified identifier already exists in + X-Plane. In that case, you can safely call XPLMCreateMapLayer() specifying + that your layer should be added to that map. + } + FUNCTION XPLMMapExists( + mapIdentifier : XPLMString) : Integer; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP DRAWING + ___________________________________________________________________________} +{ + These APIs are only valid from within a map drawing callback (one of + XPLMIconDrawingCallback_t or XPLMMapLabelDrawingCallback_f). Your drawing + callbacks are registered when you create a new map layer as part of your + XPLMCreateMapLayer_t. The functions here hook into X-Plane's built-in map + drawing functionality for icons and labels, so that you get a consistent + style with the rest of the X-Plane map. + + Note that the X-Plane 11 map introduces a strict ordering: layers of type + xplm_MapLayer_Fill get drawn beneath all xplm_MapLayer_Markings layers. + Likewise, all OpenGL drawing (performed in your layer's + XPLMMapDrawingCallback_f) will appear beneath any icons and labels you + draw. +} + + + { + XPLMMapOrientation + + Indicates whether a map element should be match its rotation to the map + itself, or to the user interface. For instance, the map itself may be + rotated such that "up" matches the user's aircraft, but you may want to + draw a text label such that it is always rotated zero degrees relative to + the user's perspective. In that case, you would have it draw with UI + orientation. + } +TYPE + XPLMMapOrientation = ( + { Orient such that a 0 degree rotation matches the map's north } + xplm_MapOrientation_Map = 0 + + { Orient such that a 0 degree rotation is "up" relative to the user interface} + ,xplm_MapOrientation_UI = 1 + + ); + PXPLMMapOrientation = ^XPLMMapOrientation; + + { + XPLMDrawMapIconFromSheet + + Enables plugin-created map layers to draw PNG icons using X-Plane's + built-in icon drawing functionality. Only valid from within an + XPLMIconDrawingCallback_t (but you can request an arbitrary number of icons + to be drawn from within your callback). + + X-Plane will automatically manage the memory for your texture so that it + only has to be loaded from disk once as long as you continue drawing it + per-frame. (When you stop drawing it, the memory may purged in a "garbage + collection" pass, require a load from disk in the future.) + + Instead of having X-Plane draw a full PNG, this method allows you to use UV + coordinates to request a portion of the image to be drawn. This allows you + to use a single texture load (of an icon sheet, for example) to draw many + icons. Doing so is much more efficient than drawing a dozen different small + PNGs. + + The UV coordinates used here treat the texture you load as being comprised + of a number of identically sized "cells." You specify the width and height + in cells (ds and dt, respectively), as well as the coordinates within the + cell grid for the sub-image you'd like to draw. + + Note that you can use different ds and dt values in subsequent calls with + the same texture sheet. This enables you to use icons of different sizes in + the same sheet if you arrange them properly in the PNG. + + This function is only valid from within an XPLMIconDrawingCallback_t (but + you can request an arbitrary number of icons to be drawn from within your + callback). + } + PROCEDURE XPLMDrawMapIconFromSheet( + layer : XPLMMapLayerID; + inPngPath : XPLMString; + s : Integer; + t : Integer; + ds : Integer; + dt : Integer; + mapX : Single; + mapY : Single; + orientation : XPLMMapOrientation; + rotationDegrees : Single; + mapWidth : Single); + cdecl; external XPLM_DLL; + + { + XPLMDrawMapLabel + + Enables plugin-created map layers to draw text labels using X-Plane's + built-in labeling functionality. Only valid from within an + XPLMMapLabelDrawingCallback_f (but you can request an arbitrary number of + text labels to be drawn from within your callback). + } + PROCEDURE XPLMDrawMapLabel( + layer : XPLMMapLayerID; + inText : XPLMString; + mapX : Single; + mapY : Single; + orientation : XPLMMapOrientation; + rotationDegrees : Single); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * MAP PROJECTIONS + ___________________________________________________________________________} +{ + As of X-Plane 11, the map draws using true cartographic projections, and + different maps may use different projections. Thus, to draw at a particular + latitude and longitude, you must first transform your real-world + coordinates into map coordinates. + + The map projection is also responsible for giving you the current scale of + the map. That is, the projection can tell you how many map units correspond + to 1 meter at a given point. + + Finally, the map projection can give you the current rotation of the map. + Since X-Plane 11 maps can rotate to match the heading of the aircraft, the + map's rotation can potentially change every frame. +} + + + { + XPLMMapProject + + Projects a latitude/longitude into map coordinates. This is the inverse of + XPLMMapUnproject(). + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + PROCEDURE XPLMMapProject( + projection : XPLMMapProjectionID; + latitude : Real; + longitude : Real; + outX : PSingle; + outY : PSingle); + cdecl; external XPLM_DLL; + + { + XPLMMapUnproject + + Transforms map coordinates back into a latitude and longitude. This is the + inverse of XPLMMapProject(). + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + PROCEDURE XPLMMapUnproject( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single; + outLatitude : PReal; + outLongitude : PReal); + cdecl; external XPLM_DLL; + + { + XPLMMapScaleMeter + + Returns the number of map units that correspond to a distance of one meter + at a given set of map coordinates. + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + FUNCTION XPLMMapScaleMeter( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single) : Single; + cdecl; external XPLM_DLL; + + { + XPLMMapGetNorthHeading + + Returns the heading (in degrees clockwise) from the positive Y axis in the + cartesian mapping coordinate system to true north at the point passed in. + You can use it as a clockwise rotational offset to align icons and other + 2-d drawing with true north on the map, compensating for rotations in the + map due to projection. + + Only valid from within a map layer callback (one of + XPLMMapPrepareCacheCallback_f, XPLMMapDrawingCallback_f, + XPLMMapIconDrawingCallback_f, or XPLMMapLabelDrawingCallback_f.) + } + FUNCTION XPLMMapGetNorthHeading( + projection : XPLMMapProjectionID; + mapX : Single; + mapY : Single) : Single; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMMenus.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMMenus.pas new file mode 100644 index 0000000..754a434 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMMenus.pas @@ -0,0 +1,277 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMMenus; +INTERFACE +{ + Plug-ins can create menus in the menu bar of X-Plane. This is done by + creating a menu and then creating items. Menus are referred to by an + opaque ID. Items are referred to by (zero-based) index number. + + Menus are "sandboxed" between plugins---no plugin can access the menus of + any other plugin. Furthermore, all menu indices are relative to your + plugin's menus only; if your plugin creates two sub-menus in the Plugins + menu at different times, it doesn't matter how many other plugins also + create sub-menus of Plugins in the intervening time: your sub-menus will be + given menu indices 0 and 1. (The SDK does some work in the back-end to + filter out menus that are irrelevant to your plugin in order to deliver + this consistency for each plugin.) + + When you create a menu item, you specify how we should handle clicks on + that menu item. You can either have the XPLM trigger a callback (the + XPLMMenuHandler_f associated with the menu that contains the item), or you + can simply have a command be triggered (with no associated call to your + menu handler). The advantage of the latter method is that X-Plane will + display any keyboard shortcuts associated with the command. (In contrast, + there are no keyboard shortcuts associated with menu handler callbacks with + specific parameters.) + + Menu text in X-Plane is UTF8; X-Plane's character set covers latin, greek + and cyrillic characters, Katakana, as well as some Japanese symbols. Some + APIs have a inDeprecatedAndIgnored parameter that used to select a + character set; since X-Plane 9 all localization is done via UTF-8 only. +} + +USES + XPLMDefs, XPLMUtilities; + {$A4} +{___________________________________________________________________________ + * XPLM MENUS + ___________________________________________________________________________} + + { + XPLMMenuCheck + + These enumerations define the various 'check' states for an X-Plane menu. + 'checking' in X-Plane actually appears as a light which may or may not be + lit. So there are three possible states. + } +TYPE + XPLMMenuCheck = ( + { there is no symbol to the left of the menu item. } + xplm_Menu_NoCheck = 0 + + { the menu has a mark next to it that is unmarked (not lit). } + ,xplm_Menu_Unchecked = 1 + + { the menu has a mark next to it that is checked (lit). } + ,xplm_Menu_Checked = 2 + + ); + PXPLMMenuCheck = ^XPLMMenuCheck; + + { + XPLMMenuID + + This is a unique ID for each menu you create. + } + XPLMMenuID = pointer; + PXPLMMenuID = ^XPLMMenuID; + + { + XPLMMenuHandler_f + + A menu handler function takes two reference pointers, one for the menu + (specified when the menu was created) and one for the item (specified when + the item was created). + } + XPLMMenuHandler_f = PROCEDURE( + inMenuRef : pointer; + inItemRef : pointer); cdecl; + + { + XPLMFindPluginsMenu + + This function returns the ID of the plug-ins menu, which is created for you + at startup. + } + FUNCTION XPLMFindPluginsMenu: XPLMMenuID; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMFindAircraftMenu + + This function returns the ID of the menu for the currently-loaded aircraft, + used for showing aircraft-specific commands. + + The aircraft menu is created by X-Plane at startup, but it remains hidden + until it is populated via XPLMAppendMenuItem() or + XPLMAppendMenuItemWithCommand(). + + Only plugins loaded with the user's current aircraft are allowed to access + the aircraft menu. For all other plugins, this will return NULL, and any + attempts to add menu items to it will fail. + } + FUNCTION XPLMFindAircraftMenu: XPLMMenuID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMCreateMenu + + This function creates a new menu and returns its ID. It returns NULL if + the menu cannot be created. Pass in a parent menu ID and an item index to + create a submenu, or NULL for the parent menu to put the menu in the menu + bar. The menu's name is only used if the menu is in the menubar. You also + pass a handler function and a menu reference value. Pass NULL for the + handler if you do not need callbacks from the menu (for example, if it only + contains submenus). + + Important: you must pass a valid, non-empty menu title even if the menu is + a submenu where the title is not visible. + } + FUNCTION XPLMCreateMenu( + inName : XPLMString; + inParentMenu : XPLMMenuID; + inParentItem : Integer; + inHandler : XPLMMenuHandler_f; + inMenuRef : pointer) : XPLMMenuID; + cdecl; external XPLM_DLL; + + { + XPLMDestroyMenu + + This function destroys a menu that you have created. Use this to remove a + submenu if necessary. (Normally this function will not be necessary.) + } + PROCEDURE XPLMDestroyMenu( + inMenuID : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMClearAllMenuItems + + This function removes all menu items from a menu, allowing you to rebuild + it. Use this function if you need to change the number of items on a menu. + } + PROCEDURE XPLMClearAllMenuItems( + inMenuID : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMAppendMenuItem + + This routine appends a new menu item to the bottom of a menu and returns + its index. Pass in the menu to add the item to, the items name, and a void + * ref for this item. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + + Note that all menu indices returned are relative to your plugin's menus + only; if your plugin creates two sub-menus in the Plugins menu at different + times, it doesn't matter how many other plugins also create sub-menus of + Plugins in the intervening time: your sub-menus will be given menu indices + 0 and 1. (The SDK does some work in the back-end to filter out menus that + are irrelevant to your plugin in order to deliver this consistency for each + plugin.) + } + FUNCTION XPLMAppendMenuItem( + inMenu : XPLMMenuID; + inItemName : XPLMString; + inItemRef : pointer; + inDeprecatedAndIgnored: Integer) : Integer; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM300} + { + XPLMAppendMenuItemWithCommand + + Like XPLMAppendMenuItem(), but instead of the new menu item triggering the + XPLMMenuHandler_f of the containiner menu, it will simply execute the + command you pass in. Using a command for your menu item allows the user to + bind a keyboard shortcut to the command and see that shortcut represented + in the menu. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + + Like XPLMAppendMenuItem(), all menu indices are relative to your plugin's + menus only. + } + FUNCTION XPLMAppendMenuItemWithCommand( + inMenu : XPLMMenuID; + inItemName : XPLMString; + inCommandToExecute : XPLMCommandRef) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} + + { + XPLMAppendMenuSeparator + + This routine adds a separator to the end of a menu. + + Returns a negative index if the append failed (due to an invalid parent + menu argument). + } + PROCEDURE XPLMAppendMenuSeparator( + inMenu : XPLMMenuID); + cdecl; external XPLM_DLL; + + { + XPLMSetMenuItemName + + This routine changes the name of an existing menu item. Pass in the menu + ID and the index of the menu item. + } + PROCEDURE XPLMSetMenuItemName( + inMenu : XPLMMenuID; + inIndex : Integer; + inItemName : XPLMString; + inDeprecatedAndIgnored: Integer); + cdecl; external XPLM_DLL; + + { + XPLMCheckMenuItem + + Set whether a menu item is checked. Pass in the menu ID and item index. + } + PROCEDURE XPLMCheckMenuItem( + inMenu : XPLMMenuID; + index : Integer; + inCheck : XPLMMenuCheck); + cdecl; external XPLM_DLL; + + { + XPLMCheckMenuItemState + + This routine returns whether a menu item is checked or not. A menu item's + check mark may be on or off, or a menu may not have an icon at all. + } + PROCEDURE XPLMCheckMenuItemState( + inMenu : XPLMMenuID; + index : Integer; + outCheck : PXPLMMenuCheck); + cdecl; external XPLM_DLL; + + { + XPLMEnableMenuItem + + Sets whether this menu item is enabled. Items start out enabled. + } + PROCEDURE XPLMEnableMenuItem( + inMenu : XPLMMenuID; + index : Integer; + enabled : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM210} + { + XPLMRemoveMenuItem + + Removes one item from a menu. Note that all menu items below are moved up + one; your plugin must track the change in index numbers. + } + PROCEDURE XPLMRemoveMenuItem( + inMenu : XPLMMenuID; + inIndex : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMNavigation.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMNavigation.pas new file mode 100644 index 0000000..044b99b --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMNavigation.pas @@ -0,0 +1,350 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMNavigation; +INTERFACE +{ + The XPLM Navigation APIs give you some access to the navigation databases + inside X-Plane. X-Plane stores all navigation information in RAM, so by + using these APIs you can gain access to most information without having to + go to disk or parse the files yourself. + + You can also use this API to program the FMS. You must use the navigation + APIs to find the nav-aids you want to program into the FMS, since the FMS + is powered internally by X-Plane's navigation database. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * NAVIGATION DATABASE ACCESS + ___________________________________________________________________________} + + { + XPLMNavType + + These enumerations define the different types of navaids. They are each + defined with a separate bit so that they may be bit-wise added together to + form sets of nav-aid types. + + NOTE: xplm_Nav_LatLon is a specific lat-lon coordinate entered into the + FMS. It will not exist in the database, and cannot be programmed into the + FMS. Querying the FMS for navaids will return it. Use + XPLMSetFMSEntryLatLon to set a lat/lon waypoint. + } +TYPE + XPLMNavType = ( + xplm_Nav_Unknown = 0 + + ,xplm_Nav_Airport = 1 + + ,xplm_Nav_NDB = 2 + + ,xplm_Nav_VOR = 4 + + ,xplm_Nav_ILS = 8 + + ,xplm_Nav_Localizer = 16 + + ,xplm_Nav_GlideSlope = 32 + + ,xplm_Nav_OuterMarker = 64 + + ,xplm_Nav_MiddleMarker = 128 + + ,xplm_Nav_InnerMarker = 256 + + ,xplm_Nav_Fix = 512 + + ,xplm_Nav_DME = 1024 + + ,xplm_Nav_LatLon = 2048 + + ); + PXPLMNavType = ^XPLMNavType; + + { + XPLMNavRef + + XPLMNavRef is an iterator into the navigation database. The navigation + database is essentially an array, but it is not necessarily densely + populated. The only assumption you can safely make is that like-typed + nav-aids are grouped together. + + Use XPLMNavRef to refer to a nav-aid. + + XPLM_NAV_NOT_FOUND is returned by functions that return an XPLMNavRef when + the iterator must be invalid. + } + XPLMNavRef = Integer; + PXPLMNavRef = ^XPLMNavRef; + +CONST + XPLM_NAV_NOT_FOUND = -1; + + { + XPLMGetFirstNavAid + + This returns the very first navaid in the database. Use this to traverse + the entire database. Returns XPLM_NAV_NOT_FOUND if the nav database is + empty. + } + FUNCTION XPLMGetFirstNavAid: XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMGetNextNavAid + + Given a valid nav aid ref, this routine returns the next navaid. It + returns XPLM_NAV_NOT_FOUND if the nav aid passed in was invalid or if the + navaid passed in was the last one in the database. Use this routine to + iterate across all like-typed navaids or the entire database. + } + FUNCTION XPLMGetNextNavAid( + inNavAidRef : XPLMNavRef) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindFirstNavAidOfType + + This routine returns the ref of the first navaid of the given type in the + database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + database. You must pass exactly one nav aid type to this routine. + } + FUNCTION XPLMFindFirstNavAidOfType( + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindLastNavAidOfType + + This routine returns the ref of the last navaid of the given type in the + database or XPLM_NAV_NOT_FOUND if there are no navaids of that type in the + database. You must pass exactly one nav aid type to this routine. + } + FUNCTION XPLMFindLastNavAidOfType( + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMFindNavAid + + This routine provides a number of searching capabilities for the nav + database. XPLMFindNavAid will search through every nav aid whose type is + within inType (multiple types may be added together) and return any + nav-aids found based on the following rules: + + * If inLat and inLon are not NULL, the navaid nearest to that lat/lon will + be returned, otherwise the last navaid found will be returned. + + * If inFrequency is not NULL, then any navaids considered must match this + frequency. Note that this will screen out radio beacons that do not have + frequency data published (like inner markers) but not fixes and airports. + + * If inNameFragment is not NULL, only navaids that contain the fragment in + their name will be returned. + + * If inIDFragment is not NULL, only navaids that contain the fragment in + their IDs will be returned. + + This routine provides a simple way to do a number of useful searches: + * Find the nearest navaid on this frequency. + * Find the nearest airport. + * Find the VOR whose ID is "KBOS". + * Find the nearest airport whose name contains "Chicago". + } + FUNCTION XPLMFindNavAid( + inNameFragment : XPLMString; { Can be nil } + inIDFragment : XPLMString; { Can be nil } + inLat : PSingle; { Can be nil } + inLon : PSingle; { Can be nil } + inFrequency : PInteger; { Can be nil } + inType : XPLMNavType) : XPLMNavRef; + cdecl; external XPLM_DLL; + + { + XPLMGetNavAidInfo + + This routine returns information about a navaid. Any non-null field is + filled out with information if it is available. + + Frequencies are in the nav.dat convention as described in the X-Plane nav + database FAQ: NDB frequencies are exact, all others are multiplied by 100. + + The buffer for IDs should be at least 6 chars and the buffer for names + should be at least 41 chars, but since these values are likely to go up, I + recommend passing at least 32 chars for IDs and 256 chars for names when + possible. + + The outReg parameter tells if the navaid is within the local "region" of + loaded DSFs. (This information may not be particularly useful to plugins.) + The parameter is a single byte value 1 for true or 0 for false, not a C + string. + } + PROCEDURE XPLMGetNavAidInfo( + inRef : XPLMNavRef; + outType : PXPLMNavType; { Can be nil } + outLatitude : PSingle; { Can be nil } + outLongitude : PSingle; { Can be nil } + outHeight : PSingle; { Can be nil } + outFrequency : PInteger; { Can be nil } + outHeading : PSingle; { Can be nil } + outID : XPLMString; { Can be nil } + outName : XPLMString; { Can be nil } + outReg : XPLMString); { Can be nil } + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * FLIGHT MANAGEMENT COMPUTER + ___________________________________________________________________________} +{ + Note: the FMS works based on an array of entries. Indices into the array + are zero-based. Each entry is a nav-aid plus an altitude. The FMS tracks + the currently displayed entry and the entry that it is flying to. + + The FMS must be programmed with contiguous entries, so clearing an entry at + the end shortens the effective flight plan. There is a max of 100 + waypoints in the flight plan. +} + + + { + XPLMCountFMSEntries + + This routine returns the number of entries in the FMS. + } + FUNCTION XPLMCountFMSEntries: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDisplayedFMSEntry + + This routine returns the index of the entry the pilot is viewing. + } + FUNCTION XPLMGetDisplayedFMSEntry: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetDestinationFMSEntry + + This routine returns the index of the entry the FMS is flying to. + } + FUNCTION XPLMGetDestinationFMSEntry: Integer; + cdecl; external XPLM_DLL; + + { + XPLMSetDisplayedFMSEntry + + This routine changes which entry the FMS is showing to the index specified. + } + PROCEDURE XPLMSetDisplayedFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetDestinationFMSEntry + + This routine changes which entry the FMS is flying the aircraft toward. + } + PROCEDURE XPLMSetDestinationFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + + { + XPLMGetFMSEntryInfo + + This routine returns information about a given FMS entry. If the entry is + an airport or navaid, a reference to a nav entry can be returned allowing + you to find additional information (such as a frequency, ILS heading, name, + etc.). Note that this reference can be XPLM_NAV_NOT_FOUND until the + information has been looked up asynchronously, so after flightplan changes, + it might take up to a second for this field to become populated. The other + information is available immediately. For a lat/lon entry, the lat/lon is + returned by this routine but the navaid cannot be looked up (and the + reference will be XPLM_NAV_NOT_FOUND). FMS name entry buffers should be at + least 256 chars in length. + + WARNING: Due to a bug in X-Plane prior to 11.31, the navaid reference will + not be set to XPLM_NAV_NOT_FOUND while no data is available, and instead + just remain the value of the variable that you passed the pointer to. + Therefore, always initialize the variable to XPLM_NAV_NOT_FOUND before + passing the pointer to this function. + } + PROCEDURE XPLMGetFMSEntryInfo( + inIndex : Integer; + outType : PXPLMNavType; { Can be nil } + outID : XPLMString; { Can be nil } + outRef : PXPLMNavRef; { Can be nil } + outAltitude : PInteger; { Can be nil } + outLat : PSingle; { Can be nil } + outLon : PSingle); { Can be nil } + cdecl; external XPLM_DLL; + + { + XPLMSetFMSEntryInfo + + This routine changes an entry in the FMS to have the destination navaid + passed in and the altitude specified. Use this only for airports, fixes, + and radio-beacon navaids. Currently of radio beacons, the FMS can only + support VORs and NDBs. Use the routines below to clear or fly to a lat/lon. + } + PROCEDURE XPLMSetFMSEntryInfo( + inIndex : Integer; + inRef : XPLMNavRef; + inAltitude : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetFMSEntryLatLon + + This routine changes the entry in the FMS to a lat/lon entry with the given + coordinates. + } + PROCEDURE XPLMSetFMSEntryLatLon( + inIndex : Integer; + inLat : Single; + inLon : Single; + inAltitude : Integer); + cdecl; external XPLM_DLL; + + { + XPLMClearFMSEntry + + This routine clears the given entry, potentially shortening the flight + plan. + } + PROCEDURE XPLMClearFMSEntry( + inIndex : Integer); + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * GPS RECEIVER + ___________________________________________________________________________} +{ + These APIs let you read data from the GPS unit. +} + + { + XPLMGetGPSDestinationType + + This routine returns the type of the currently selected GPS destination, + one of fix, airport, VOR or NDB. + } + FUNCTION XPLMGetGPSDestinationType: XPLMNavType; + cdecl; external XPLM_DLL; + + { + XPLMGetGPSDestination + + This routine returns the current GPS destination. + } + FUNCTION XPLMGetGPSDestination: XPLMNavRef; + cdecl; external XPLM_DLL; + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMPlanes.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMPlanes.pas new file mode 100644 index 0000000..3801f0a --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMPlanes.pas @@ -0,0 +1,278 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMPlanes; +INTERFACE +{ + The XPLMPlanes APIs allow you to control the various aircraft in X-Plane, + both the user's and the sim's. + + *Note*: unlike almost all other APIs in the SDK, aircraft paths are _full_ + file system paths for historical reasons. You'll need to prefix all + relative paths with the X-Plane path as accessed via XPLMGetSystemPath. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * USER AIRCRAFT ACCESS + ___________________________________________________________________________} + + { + XPLMSetUsersAircraft + + This routine changes the user's aircraft. Note that this will reinitialize + the user to be on the nearest airport's first runway. Pass in a full path + (hard drive and everything including the .acf extension) to the .acf file. + } + PROCEDURE XPLMSetUsersAircraft( + inAircraftPath : XPLMString); + cdecl; external XPLM_DLL; + { + XPLMPlaceUserAtAirport + + This routine places the user at a given airport. Specify the airport by + its X-Plane airport ID (e.g. 'KBOS'). + } + PROCEDURE XPLMPlaceUserAtAirport( + inAirportCode : XPLMString); + cdecl; external XPLM_DLL; +{$IFDEF XPLM300} + { + XPLMPlaceUserAtLocation + + Places the user at a specific location after performing any necessary + scenery loads. + + As with in-air starts initiated from the X-Plane user interface, the + aircraft will always start with its engines running, regardless of the + user's preferences (i.e., regardless of what the dataref + `sim/operation/prefs/startup_running` says). + } + PROCEDURE XPLMPlaceUserAtLocation( + latitudeDegrees : Real; + longitudeDegrees : Real; + elevationMetersMSL : Single; + headingDegreesTrue : Single; + speedMetersPerSecond: Single); + cdecl; external XPLM_DLL; +{$ENDIF XPLM300} +{___________________________________________________________________________ + * GLOBAL AIRCRAFT ACCESS + ___________________________________________________________________________} + +CONST + { The user's aircraft is always index 0. } + XPLM_USER_AIRCRAFT = 0; +{$IFDEF XPLM_DEPRECATED} + { + XPLMPlaneDrawState_t + + This structure contains additional plane parameter info to be passed to + draw plane. Make sure to fill in the size of the structure field with + sizeof(XPLMDrawPlaneState_t) so that the XPLM can tell how many fields you + knew about when compiling your plugin (since more fields may be added + later). + + Most of these fields are ratios from 0 to 1 for control input. X-Plane + calculates what the actual controls look like based on the .acf file for + that airplane. Note for the yoke inputs, this is what the pilot of the + plane has commanded (post artificial stability system if there were one) + and affects aelerons, rudder, etc. It is not necessarily related to the + actual position of the plane! + } +TYPE + XPLMPlaneDrawState_t = RECORD + { The size of the draw state struct. } + structSize : Integer; + { A ratio from [0..1] describing how far the landing gear is extended. } + gearPosition : Single; + { Ratio of flap deployment, 0 = up, 1 = full deploy. } + flapRatio : Single; + { Ratio of spoiler deployment, 0 = none, 1 = full deploy. } + spoilerRatio : Single; + { Ratio of speed brake deployment, 0 = none, 1 = full deploy. } + speedBrakeRatio : Single; + { Ratio of slat deployment, 0 = none, 1 = full deploy. } + slatRatio : Single; + { Wing sweep ratio, 0 = forward, 1 = swept. } + wingSweep : Single; + { Thrust power, 0 = none, 1 = full fwd, -1 = full reverse. } + thrust : Single; + { Total pitch input for this plane. } + yokePitch : Single; + { Total Heading input for this plane. } + yokeHeading : Single; + { Total Roll input for this plane. } + yokeRoll : Single; + END; + PXPLMPlaneDrawState_t = ^XPLMPlaneDrawState_t; +{$ENDIF XPLM_DEPRECATED} + { + XPLMCountAircraft + + This function returns the number of aircraft X-Plane is capable of having, + as well as the number of aircraft that are currently active. These numbers + count the user's aircraft. It can also return the plugin that is currently + controlling aircraft. In X-Plane 7, this routine reflects the number of + aircraft the user has enabled in the rendering options window. + } + PROCEDURE XPLMCountAircraft( + outTotalAircraft : PInteger; + outActiveAircraft : PInteger; + outController : PXPLMPluginID); + cdecl; external XPLM_DLL; + { + XPLMGetNthAircraftModel + + This function returns the aircraft model for the Nth aircraft. Indices are + zero based, with zero being the user's aircraft. The file name should be + at least 256 chars in length; the path should be at least 512 chars in + length. + } + PROCEDURE XPLMGetNthAircraftModel( + inIndex : Integer; + outFileName : XPLMString; + outPath : XPLMString); + cdecl; external XPLM_DLL; +{___________________________________________________________________________ + * EXCLUSIVE AIRCRAFT ACCESS + ___________________________________________________________________________} +{ + The following routines require exclusive access to the airplane APIs. Only + one plugin may have this access at a time. +} + + + { + XPLMPlanesAvailable_f + + Your airplanes available callback is called when another plugin gives up + access to the multiplayer planes. Use this to wait for access to + multiplayer. + } +TYPE + XPLMPlanesAvailable_f = PROCEDURE( + inRefcon : pointer); cdecl; + + { + XPLMAcquirePlanes + + XPLMAcquirePlanes grants your plugin exclusive access to the aircraft. It + returns 1 if you gain access, 0 if you do not. + + inAircraft - pass in an array of pointers to strings specifying the planes + you want loaded. For any plane index you do not want loaded, pass a + 0-length string. Other strings should be full paths with the .acf + extension. NULL terminates this array, or pass NULL if there are no planes + you want loaded. + + If you pass in a callback and do not receive access to the planes your + callback will be called when the airplanes are available. If you do receive + airplane access, your callback will not be called. + } + FUNCTION XPLMAcquirePlanes( + inAircraft : PXPLMString; { Can be nil } + inCallback : XPLMPlanesAvailable_f; + inRefcon : pointer) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMReleasePlanes + + Call this function to release access to the planes. Note that if you are + disabled, access to planes is released for you and you must reacquire it. + } + PROCEDURE XPLMReleasePlanes; + cdecl; external XPLM_DLL; + + { + XPLMSetActiveAircraftCount + + This routine sets the number of active planes. If you pass in a number + higher than the total number of planes availables, only the total number of + planes available is actually used. + } + PROCEDURE XPLMSetActiveAircraftCount( + inCount : Integer); + cdecl; external XPLM_DLL; + + { + XPLMSetAircraftModel + + This routine loads an aircraft model. It may only be called if you have + exclusive access to the airplane APIs. Pass in the path of the model with + the .acf extension. The index is zero based, but you may not pass in 0 + (use XPLMSetUsersAircraft to load the user's aircracft). + } + PROCEDURE XPLMSetAircraftModel( + inIndex : Integer; + inAircraftPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMDisableAIForPlane + + This routine turns off X-Plane's AI for a given plane. The plane will + continue to draw and be a real plane in X-Plane, but will not move itself. + } + PROCEDURE XPLMDisableAIForPlane( + inPlaneIndex : Integer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM_DEPRECATED} + { + XPLMDrawAircraft + + WARNING: Aircraft drawing via this API is deprecated and will not work in + future versions of X-Plane. Use XPLMInstance for 3-d drawing of custom + aircraft models. + + This routine draws an aircraft. It can only be called from a 3-d drawing + callback. Pass in the position of the plane in OpenGL local coordinates + and the orientation of the plane. A 1 for full drawing indicates that the + whole plane must be drawn; a 0 indicates you only need the nav lights + drawn. (This saves rendering time when planes are far away.) + } + PROCEDURE XPLMDrawAircraft( + inPlaneIndex : Integer; + inX : Single; + inY : Single; + inZ : Single; + inPitch : Single; + inRoll : Single; + inYaw : Single; + inFullDraw : Integer; + inDrawStateInfo : PXPLMPlaneDrawState_t); + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMReinitUsersPlane + + WARNING: DO NOT USE. Use XPLMPlaceUserAtAirport or + XPLMPlaceUserAtLocation. + + This function recomputes the derived flight model data from the aircraft + structure in memory. If you have used the data access layer to modify the + aircraft structure, use this routine to resynchronize X-Plane; since + X-Plane works at least partly from derived values, the sim will not behave + properly until this is called. + + WARNING: this routine does not necessarily place the airplane at the + airport; use XPLMSetUsersAircraft to be compatible. This routine is + provided to do special experimentation with flight models without resetting + flight. + } + PROCEDURE XPLMReinitUsersPlane; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMPlugin.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMPlugin.pas new file mode 100644 index 0000000..83fbb73 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMPlugin.pas @@ -0,0 +1,413 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMPlugin; +INTERFACE +{ + These APIs provide facilities to find and work with other plugins and + manage other plugins. +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FINDING PLUGINS + ___________________________________________________________________________} +{ + These APIs allow you to find another plugin or yourself, or iterate across + all plugins. For example, if you wrote an FMS plugin that needed to talk + to an autopilot plugin, you could use these APIs to locate the autopilot + plugin. +} + + + { + XPLMGetMyID + + This routine returns the plugin ID of the calling plug-in. Call this to + get your own ID. + } + FUNCTION XPLMGetMyID: XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMCountPlugins + + This routine returns the total number of plug-ins that are loaded, both + disabled and enabled. + } + FUNCTION XPLMCountPlugins: Integer; + cdecl; external XPLM_DLL; + + { + XPLMGetNthPlugin + + This routine returns the ID of a plug-in by index. Index is 0 based from 0 + to XPLMCountPlugins-1, inclusive. Plugins may be returned in any arbitrary + order. + } + FUNCTION XPLMGetNthPlugin( + inIndex : Integer) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMFindPluginByPath + + This routine returns the plug-in ID of the plug-in whose file exists at the + passed in absolute file system path. XPLM_NO_PLUGIN_ID is returned if the + path does not point to a currently loaded plug-in. + } + FUNCTION XPLMFindPluginByPath( + inPath : XPLMString) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMFindPluginBySignature + + This routine returns the plug-in ID of the plug-in whose signature matches + what is passed in or XPLM_NO_PLUGIN_ID if no running plug-in has this + signature. Signatures are the best way to identify another plug-in as they + are independent of the file system path of a plug-in or the human-readable + plug-in name, and should be unique for all plug-ins. Use this routine to + locate another plugin that your plugin interoperates with + } + FUNCTION XPLMFindPluginBySignature( + inSignature : XPLMString) : XPLMPluginID; + cdecl; external XPLM_DLL; + + { + XPLMGetPluginInfo + + This routine returns information about a plug-in. Each parameter should be + a pointer to a buffer of at least + 256 characters, or NULL to not receive the information. + + outName - the human-readable name of the plug-in. outFilePath - the + absolute file path to the file that contains this plug-in. outSignature - a + unique string that identifies this plug-in. outDescription - a + human-readable description of this plug-in. + } + PROCEDURE XPLMGetPluginInfo( + inPlugin : XPLMPluginID; + outName : XPLMString; { Can be nil } + outFilePath : XPLMString; { Can be nil } + outSignature : XPLMString; { Can be nil } + outDescription : XPLMString); { Can be nil } + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * ENABLING/DISABLING PLUG-INS + ___________________________________________________________________________} +{ + These routines are used to work with plug-ins and manage them. Most + plugins will not need to use these APIs. +} + + + { + XPLMIsPluginEnabled + + Returns whether the specified plug-in is enabled for running. + } + FUNCTION XPLMIsPluginEnabled( + inPluginID : XPLMPluginID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMEnablePlugin + + This routine enables a plug-in if it is not already enabled. It returns 1 + if the plugin was enabled or successfully enables itself, 0 if it does not. + Plugins may fail to enable (for example, if resources cannot be acquired) + by returning 0 from their XPluginEnable callback. + } + FUNCTION XPLMEnablePlugin( + inPluginID : XPLMPluginID) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMDisablePlugin + + This routine disableds an enabled plug-in. + } + PROCEDURE XPLMDisablePlugin( + inPluginID : XPLMPluginID); + cdecl; external XPLM_DLL; + + { + XPLMReloadPlugins + + This routine reloads all plug-ins. Once this routine is called and you + return from the callback you were within (e.g. a menu select callback) you + will receive your XPluginDisable and XPluginStop callbacks and your DLL + will be unloaded, then the start process happens as if the sim was starting + up. + } + PROCEDURE XPLMReloadPlugins; + cdecl; external XPLM_DLL; + +{___________________________________________________________________________ + * INTERPLUGIN MESSAGING + ___________________________________________________________________________} +{ + Plugin messages are defined as 32-bit integers. Messages below 0x00FFFFFF + are reserved for X-Plane and the plugin SDK. + + Messages come with a pointer parameter; the meaning of this pointer depends + on the message itself. In some messages, the pointer parameter contains an + actual typed pointer to data that can be inspected in the plugin; in these + cases the documentation will state that the parameter "points to" + information. + + in other cases, the value of the pointer is actually an integral number + stuffed into the pointer's storage. In these second cases, the pointer + parameter needs to be cast, not dereferenced. In these caess, the + documentation will state that the parameter "contains" a value, which will + always be an integral type. + + Some messages don't use the pointer parameter - in this case your plugin + should ignore it. + + Messages have two conceptual uses: notifications and commands. Commands + are sent from one plugin to another to induce behavior; notifications are + sent from one plugin to all others for informational purposes. It is + important that commands and notifications not have the same values because + this could cause a notification sent by one plugin to accidentally induce a + command in another. + + By convention, plugin-defined notifications should have the high bit set + (e.g. be greater or equal to unsigned 0x8000000) while commands should have + this bit be cleared. + + The following messages are sent to your plugin by X-Plane. +} + + +CONST + { This message is sent to your plugin whenever the user's plane crashes. The } + { parameter is ignored. } + XPLM_MSG_PLANE_CRASHED = 101; + + { This message is sent to your plugin whenever a new plane is loaded. The } + { parameter contains the index number of the plane being loaded; 0 indicates } + { the user's plane. } + XPLM_MSG_PLANE_LOADED = 102; + + { This messages is sent whenever the user's plane is positioned at a new } + { airport. The parameter is ignored. } + XPLM_MSG_AIRPORT_LOADED = 103; + + { This message is sent whenever new scenery is loaded. Use datarefs to } + { determine the new scenery files that were loaded. The parameter is ignored.} + XPLM_MSG_SCENERY_LOADED = 104; + + { This message is sent whenever the user adjusts the number of X-Plane } + { aircraft models. You must use XPLMCountPlanes to find out how many planes } + { are now available. This message will only be sent in XP7 and higher } + { because in XP6 the number of aircraft is not user-adjustable. The parameter} + { is ignored. } + XPLM_MSG_AIRPLANE_COUNT_CHANGED = 105; + +{$IFDEF XPLM200} +CONST + { This message is sent to your plugin whenever a plane is unloaded. The } + { parameter contains the index number of the plane being unloaded; 0 } + { indicates the user's plane. The parameter is of type int, passed as the } + { value of the pointer. (That is: the parameter is an int, not a pointer to } + { an int.) } + XPLM_MSG_PLANE_UNLOADED = 106; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} +CONST + { This message is sent to your plugin right before X-Plane writes its } + { preferences file. You can use this for two purposes: to write your own } + { preferences, and to modify any datarefs to influence preferences output. } + { For example, if your plugin temporarily modifies saved preferences, you can} + { put them back to their default values here to avoid having the tweaks be } + { persisted if your plugin is not loaded on the next invocation of X-Plane. } + { The parameter is ignored. } + XPLM_MSG_WILL_WRITE_PREFS = 107; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { This message is sent to your plugin right after a livery is loaded for an } + { airplane. You can use this to check the new livery (via datarefs) and } + { react accordingly. The parameter contains the index number of the aircraft} + { whose livery is changing. } + XPLM_MSG_LIVERY_LOADED = 108; +{$ENDIF XPLM210} + +{$IFDEF XPLM301} +CONST + { Sent to your plugin right before X-Plane enters virtual reality mode (at } + { which time any windows that are not positioned in VR mode will no longer be} + { visible to the user). The parameter is unused and should be ignored. } + XPLM_MSG_ENTERED_VR = 109; +{$ENDIF XPLM301} + +{$IFDEF XPLM301} + { Sent to your plugin right before X-Plane leaves virtual reality mode (at } + { which time you may want to clean up windows that are positioned in VR } + { mode). The parameter is unused and should be ignored. } + XPLM_MSG_EXITING_VR = 110; +{$ENDIF XPLM301} + +{$IFDEF XPLM303} +CONST + { Sent to your plugin if another plugin wants to take over AI planes. If you } + { are a synthetic traffic provider, that probably means a plugin for an } + { online network has connected and wants to supply aircraft flown by real } + { humans and you should cease to provide synthetic traffic. If however you } + { are providing online traffic from real humans, you probably don't want to } + { disconnect, in which case you just ignore this message. The sender is the } + { plugin ID of the plugin asking for control of the planes now. You can use } + { it to find out who is requesting and whether you should yield to them. } + { Synthetic traffic providers should always yield to online networks. The } + { parameter is unused and should be ignored. } + XPLM_MSG_RELEASE_PLANES = 111; +{$ENDIF XPLM303} + + { + XPLMSendMessageToPlugin + + This function sends a message to another plug-in or X-Plane. Pass + XPLM_NO_PLUGIN_ID to broadcast to all plug-ins. Only enabled plug-ins with + a message receive function receive the message. + } + PROCEDURE XPLMSendMessageToPlugin( + inPlugin : XPLMPluginID; + inMessage : Integer; + inParam : pointer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Plugin Features API + ___________________________________________________________________________} +{ + The plugin features API allows your plugin to "sign up" for additional + capabilities and plugin system features that are normally disabled for + backward compatibility. This allows advanced plugins to "opt-in" to new + behavior. + + Each feature is defined by a permanent string name. The feature string + names will vary with the particular installation of X-Plane, so plugins + should not expect a feature to be guaranteed present. + + XPLM_WANTS_REFLECTIONS + ---------------------- + + Available in the SDK 2.0 and later for X-Plane 9, enabling this capability + causes your plugin to receive drawing hook callbacks when X-Plane builds + its off-screen reflection and shadow rendering passes. Plugins should + enable this and examine the dataref sim/graphics/view/plane_render_type to + determine whether the drawing callback is for a reflection, shadow + calculation, or the main screen. Rendering can be simlified or omitted for + reflections, and non-solid drawing should be skipped for shadow + calculations. + + **Note**: direct drawing via draw callbacks is not recommended; use the + XPLMInstance API to create object models instead. + + XPLM_USE_NATIVE_PATHS + --------------------- + + available in the SDK 2.1 and later for X-Plane 10, this modifies the plugin + system to use Unix-style paths on all operating systems. With this enabled: + + * OS X paths will match the native OS X Unix. + * Windows will use forward slashes but preserve C:\ or another drive letter + when using complete file paths. + * Linux uses its native file system path scheme. + + Without this enabled: + + * OS X will use CFM file paths separated by a colon. + * Windows will use back-slashes and conventional DOS paths. + * Linux uses its native file system path scheme. + + All plugins should enable this feature on OS X to access the native file + system. + + XPLM_USE_NATIVE_WIDGET_WINDOWS + ------------------------------ + + Available in the SDK 3.0.2 SDK, this capability tells the widgets library + to use new, modern X-Plane backed XPLMDisplay windows to anchor all widget + trees. Without it, widgets will always use legacy windows. + + Plugins should enable this to allow their widget hierarchies to respond to + the user's UI size settings and to map widget-based windwos to a VR HMD. + + Before enabling this, make sure any custom widget code in your plugin is + prepared to cope with the UI coordinate system not being th same as the + OpenGL window coordinate system. +} + + + { + XPLMFeatureEnumerator_f + + You pass an XPLMFeatureEnumerator_f to get a list of all features supported + by a given version running version of X-Plane. This routine is called once + for each feature. + } +TYPE + XPLMFeatureEnumerator_f = PROCEDURE( + inFeature : XPLMString; + inRef : pointer); cdecl; + + { + XPLMHasFeature + + This returns 1 if the given installation of X-Plane supports a feature, or + 0 if it does not. + } + FUNCTION XPLMHasFeature( + inFeature : XPLMString) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMIsFeatureEnabled + + This returns 1 if a feature is currently enabled for your plugin, or 0 if + it is not enabled. It is an error to call this routine with an unsupported + feature. + } + FUNCTION XPLMIsFeatureEnabled( + inFeature : XPLMString) : Integer; + cdecl; external XPLM_DLL; + + { + XPLMEnableFeature + + This routine enables or disables a feature for your plugin. This will + change the running behavior of X-Plane and your plugin in some way, + depending on the feature. + } + PROCEDURE XPLMEnableFeature( + inFeature : XPLMString; + inEnable : Integer); + cdecl; external XPLM_DLL; + + { + XPLMEnumerateFeatures + + This routine calls your enumerator callback once for each feature that this + running version of X-Plane supports. Use this routine to determine all of + the features that X-Plane can support. + } + PROCEDURE XPLMEnumerateFeatures( + inEnumerator : XPLMFeatureEnumerator_f; + inRef : pointer); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMProcessing.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMProcessing.pas new file mode 100644 index 0000000..e09b6e5 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMProcessing.pas @@ -0,0 +1,254 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMProcessing; +INTERFACE +{ + This API allows you to get regular callbacks during the flight loop, the + part of X-Plane where the plane's position calculates the physics of + flight, etc. Use these APIs to accomplish periodic tasks like logging data + and performing I/O. + + You can receive a callback either just before or just after the per-frame + physics calculations happen - you can use post-FM callbacks to "patch" the + flight model after it has run. + + If the user has set the number of flight model iterations per frame greater + than one your plugin will _not_ see this; these integrations run on the + sub-section of the flight model where iterations improve responsiveness + (e.g. physical integration, not simple systems tracking) and are thus + opaque to plugins. + + Flight loop scheduling, when scheduled by time, is scheduled by a "first + callback after the deadline" schedule, e.g. your callbacks will always be + slightly late to ensure that we don't run faster than your deadline. + + WARNING: Do NOT use these callbacks to draw! You cannot draw during flight + loop callbacks. Use the drawing callbacks (see XPLMDisplay for more info) + for graphics. (One exception: you can use a post-flight loop callback to + update your own off-screen FBOs.) +} + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FLIGHT LOOP CALLBACKS + ___________________________________________________________________________} + +{$IFDEF XPLM210} + { + XPLMFlightLoopPhaseType + + You can register a flight loop callback to run either before or after the + flight model is integrated by X-Plane. + } +TYPE + XPLMFlightLoopPhaseType = ( + { Your callback runs before X-Plane integrates the flight model. } + xplm_FlightLoop_Phase_BeforeFlightModel = 0 + + { Your callback runs after X-Plane integrates the flight model. } + ,xplm_FlightLoop_Phase_AfterFlightModel = 1 + + ); + PXPLMFlightLoopPhaseType = ^XPLMFlightLoopPhaseType; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMFlightLoopID + + This is an opaque identifier for a flight loop callback. You can use this + identifier to easily track and remove your callbacks, or to use the new + flight loop APIs. + } + XPLMFlightLoopID = pointer; + PXPLMFlightLoopID = ^XPLMFlightLoopID; +{$ENDIF XPLM210} + + { + XPLMFlightLoop_f + + This is your flight loop callback. Each time the flight loop is iterated + through, you receive this call at the end. + + Flight loop callbacks receive a number of input timing parameters. These + input timing parameters are not particularly useful; you may need to track + your own timing data (e.g. by reading datarefs). The input parameters are: + + - inElapsedSinceLastCall: the wall time since your last callback. + - inElapsedTimeSinceLastFlightLoop: the wall time since any flight loop was + dispatched. + - inCounter: a monotonically increasing counter, bumped once per flight + loop dispatch from the sim. + - inRefcon: your own ptr constant from when you regitered yor callback. + + Your return value controls when you will next be called. + + - Return 0 to stop receiving callbacks. + - Pass a positive number to specify how many seconds until the next + callback. (You will be called at or after this time, not before.) + - Pass a negative number to specify how many loops must go by until you + are called. For example, -1.0 means call me the very next loop. + + Try to run your flight loop as infrequently as is practical, and suspend it + (using return value 0) when you do not need it; lots of flight loop + callbacks that do nothing lowers X-Plane's frame rate. + + Your callback will NOT be unregistered if you return 0; it will merely be + inactive. + } +TYPE + XPLMFlightLoop_f = FUNCTION( + inElapsedSinceLastCall: Single; + inElapsedTimeSinceLastFlightLoop: Single; + inCounter : Integer; + inRefcon : pointer) : Single; cdecl; + +{$IFDEF XPLM210} + { + XPLMCreateFlightLoop_t + + XPLMCreateFlightLoop_t contains the parameters to create a new flight loop + callback. The strsucture can be expanded in future SDKs - always set + structSize to the size of your structure in bytes. + } +TYPE + XPLMCreateFlightLoop_t = RECORD + structSize : Integer; + phase : XPLMFlightLoopPhaseType; + callbackFunc : XPLMFlightLoop_f; + refcon : pointer; + END; + PXPLMCreateFlightLoop_t = ^XPLMCreateFlightLoop_t; +{$ENDIF XPLM210} + + { + XPLMGetElapsedTime + + This routine returns the elapsed time since the sim started up in decimal + seconds. This is a wall timer; it keeps counting upward even if the sim is + pasued. + + __WARNING__: XPLMGetElapsedTime is not a very good timer! It lacks + precision in both its data type and its source. Do not attempt to use it + for timing critical applications like network multiplayer. + } + FUNCTION XPLMGetElapsedTime: Single; + cdecl; external XPLM_DLL; + + { + XPLMGetCycleNumber + + This routine returns a counter starting at zero for each sim cycle + computed/video frame rendered. + } + FUNCTION XPLMGetCycleNumber: Integer; + cdecl; external XPLM_DLL; + + { + XPLMRegisterFlightLoopCallback + + This routine registers your flight loop callback. Pass in a pointer to a + flight loop function and a refcon. inInterval defines when you will be + called. Pass in a positive number to specify seconds from registration time + to the next callback. Pass in a negative number to indicate when you will + be called (e.g. pass -1 to be called at the next cylcle). Pass 0 to not be + called; your callback will be inactive. + + (This legacy function only installs pre-flight-loop callbacks; use + XPLMCreateFlightLoop for more control.) + } + PROCEDURE XPLMRegisterFlightLoopCallback( + inFlightLoop : XPLMFlightLoop_f; + inInterval : Single; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMUnregisterFlightLoopCallback + + This routine unregisters your flight loop callback. Do NOT call it from + your flight loop callback. Once your flight loop callback is unregistered, + it will not be called again. + + Only use this on flight loops registered via + XPLMRegisterFlightLoopCallback. + } + PROCEDURE XPLMUnregisterFlightLoopCallback( + inFlightLoop : XPLMFlightLoop_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMSetFlightLoopCallbackInterval + + This routine sets when a callback will be called. Do NOT call it from your + callback; use the return value of the callback to change your callback + interval from inside your callback. + + inInterval is formatted the same way as in XPLMRegisterFlightLoopCallback; + positive for seconds, negative for cycles, and 0 for deactivating the + callback. If inRelativeToNow is 1, times are from the time of this call; + otherwise they are from the time the callback was last called (or the time + it was registered if it has never been called. + } + PROCEDURE XPLMSetFlightLoopCallbackInterval( + inFlightLoop : XPLMFlightLoop_f; + inInterval : Single; + inRelativeToNow : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + +{$IFDEF XPLM210} + { + XPLMCreateFlightLoop + + This routine creates a flight loop callback and returns its ID. The flight + loop callback is created using the input param struct, and is inited to be + unscheduled. + } + FUNCTION XPLMCreateFlightLoop( + inParams : PXPLMCreateFlightLoop_t) : XPLMFlightLoopID; + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMDestroyFlightLoop + + This routine destroys a flight loop callback by ID. Only call it on flight + loops created with the newer XPLMCreateFlightLoop API. + } + PROCEDURE XPLMDestroyFlightLoop( + inFlightLoopID : XPLMFlightLoopID); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM210} + { + XPLMScheduleFlightLoop + + This routine schedules a flight loop callback for future execution. If + inInterval is negative, it is run in a certain number of frames based on + the absolute value of the input. If the interval is positive, it is a + duration in seconds. + + If inRelativeToNow is true, ties are interpretted relative to the time this + routine is called; otherwise they are relative to the last call time or the + time the flight loop was registered (if never called). + } + PROCEDURE XPLMScheduleFlightLoop( + inFlightLoopID : XPLMFlightLoopID; + inInterval : Single; + inRelativeToNow : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMScenery.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMScenery.pas new file mode 100644 index 0000000..a585830 --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMScenery.pas @@ -0,0 +1,434 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMScenery; +INTERFACE +{ + This package contains APIs to interact with X-Plane's scenery system. +} + +USES + XPLMDefs; + {$A4} +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Terrain Y-Testing + ___________________________________________________________________________} +{ + The Y-testing API allows you to locate the physical scenery mesh. This + would be used to place dynamic graphics on top of the ground in a plausible + way or do physics interactions. + + The Y-test API works via probe objects, which are allocated by your plugin + and used to query terrain. Probe objects exist both to capture which + algorithm you have requested (see probe types) and also to cache query + information. + + Performance Guidelines + ---------------------- + + It is generally faster to use the same probe for nearby points and + different probes for different points. Try not to allocate more than + "hundreds" of probes at most. Share probes if you need more. Generally, + probing operations are expensive, and should be avoided via caching when + possible. + + Y testing returns a location on the terrain, a normal vectory, and a + velocity vector. The normal vector tells you the slope of the terrain at + that point. The velocity vector tells you if that terrain is moving (and is + in meters/second). For example, if your Y test hits the aircraft carrier + deck, this tells you the velocity of that point on the deck. + + Note: the Y-testing API is limited to probing the loaded scenery area, + which is approximately 300x300 km in X-Plane 9. Probes outside this area + will return the height of a 0 MSL sphere. +} + + + { + XPLMProbeType + + XPLMProbeType defines the type of terrain probe - each probe has a + different algorithm. (Only one type of probe is provided right now, but + future APIs will expose more flexible or poewrful or useful probes. + } +TYPE + XPLMProbeType = ( + { The Y probe gives you the location of the tallest physical scenery along } + { the Y axis going through the queried point. } + xplm_ProbeY = 0 + + ); + PXPLMProbeType = ^XPLMProbeType; + + { + XPLMProbeResult + + Probe results - possible results from a probe query. + } + XPLMProbeResult = ( + { The probe hit terrain and returned valid values. } + xplm_ProbeHitTerrain = 0 + + { An error in the API call. Either the probe struct size is bad, or the } + { probe is invalid or the type is mismatched for the specific query call. } + ,xplm_ProbeError = 1 + + { The probe call succeeded but there is no terrain under this point (perhaps } + { it is off the side of the planet?) } + ,xplm_ProbeMissed = 2 + + ); + PXPLMProbeResult = ^XPLMProbeResult; + + { + XPLMProbeRef + + An XPLMProbeRef is an opaque handle to a probe, used for querying the + terrain. + } + XPLMProbeRef = pointer; + PXPLMProbeRef = ^XPLMProbeRef; + + { + XPLMProbeInfo_t + + XPLMProbeInfo_t contains the results of a probe call. Make sure to set + structSize to the size of the struct before using it. + } + XPLMProbeInfo_t = RECORD + { Size of structure in bytes - always set this before calling the XPLM. } + structSize : Integer; + { Resulting X location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationX : Single; + { Resulting Y location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationY : Single; + { Resulting Z location of the terrain point we hit, in local OpenGL } + { coordinates. } + locationZ : Single; + { X component of the normal vector to the terrain we found. } + normalX : Single; + { Y component of the normal vector to the terrain we found. } + normalY : Single; + { Z component of the normal vector to the terrain we found. } + normalZ : Single; + { X component of the velocity vector of the terrain we found. } + velocityX : Single; + { Y component of the velocity vector of the terrain we found. } + velocityY : Single; + { Z component of the velocity vector of the terrain we found. } + velocityZ : Single; + { Tells if the surface we hit is water (otherwise it is land). } + is_wet : Integer; + END; + PXPLMProbeInfo_t = ^XPLMProbeInfo_t; + + { + XPLMCreateProbe + + Creates a new probe object of a given type and returns. + } + FUNCTION XPLMCreateProbe( + inProbeType : XPLMProbeType) : XPLMProbeRef; + cdecl; external XPLM_DLL; + + { + XPLMDestroyProbe + + Deallocates an existing probe object. + } + PROCEDURE XPLMDestroyProbe( + inProbe : XPLMProbeRef); + cdecl; external XPLM_DLL; + + { + XPLMProbeTerrainXYZ + + Probes the terrain. Pass in the XYZ coordinate of the probe point, a probe + object, and an XPLMProbeInfo_t struct that has its structSize member set + properly. Other fields are filled in if we hit terrain, and a probe result + is returned. + } + FUNCTION XPLMProbeTerrainXYZ( + inProbe : XPLMProbeRef; + inX : Single; + inY : Single; + inZ : Single; + outInfo : PXPLMProbeInfo_t) : XPLMProbeResult; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} +{$IFDEF XPLM300} +{___________________________________________________________________________ + * Magnetic Variation + ___________________________________________________________________________} +{ + Use the magnetic variation (more properly, the "magnetic declination") API + to find the offset of magnetic north from true north at a given latitude + and longitude within the simulator. + + In the real world, the Earth's magnetic field is irregular, such that true + north (the direction along a meridian toward the north pole) does not + necessarily match what a magnetic compass shows as north. + + Using this API ensures that you present the same offsets to users as + X-Plane's built-in instruments. +} + + + { + XPLMGetMagneticVariation + + Returns X-Plane's simulated magnetic variation (declination) at the + indication latitude and longitude. + } + FUNCTION XPLMGetMagneticVariation( + latitude : Real; + longitude : Real) : Single; + cdecl; external XPLM_DLL; + + { + XPLMDegTrueToDegMagnetic + + Converts a heading in degrees relative to true north into a value relative + to magnetic north at the user's current location. + } + FUNCTION XPLMDegTrueToDegMagnetic( + headingDegreesTrue : Single) : Single; + cdecl; external XPLM_DLL; + + { + XPLMDegMagneticToDegTrue + + Converts a heading in degrees relative to magnetic north at the user's + current location into a value relative to true north. + } + FUNCTION XPLMDegMagneticToDegTrue( + headingDegreesMagnetic: Single) : Single; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM300} +{___________________________________________________________________________ + * Object Drawing + ___________________________________________________________________________} +{ + The object drawing routines let you load and draw X-Plane OBJ files. + Objects are loaded by file path and managed via an opaque handle. X-Plane + naturally reference counts objects, so it is important that you balance + every successful call to XPLMLoadObject with a call to XPLMUnloadObject! +} + + +{$IFDEF XPLM200} +TYPE + { + XPLMObjectRef + + An XPLMObjectRef is a opaque handle to an .obj file that has been loaded + into memory. + } + XPLMObjectRef = pointer; + PXPLMObjectRef = ^XPLMObjectRef; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMDrawInfo_t + + The XPLMDrawInfo_t structure contains positioning info for one object that + is to be drawn. Be sure to set structSize to the size of the structure for + future expansion. + } + XPLMDrawInfo_t = RECORD + { Set this to the size of this structure! } + structSize : Integer; + { X location of the object in local coordinates. } + x : Single; + { Y location of the object in local coordinates. } + y : Single; + { Z location of the object in local coordinates. } + z : Single; + { Pitch in degres to rotate the object, positive is up. } + pitch : Single; + { Heading in local coordinates to rotate the object, clockwise. } + heading : Single; + { Roll to rotate the object. } + roll : Single; + END; + PXPLMDrawInfo_t = ^XPLMDrawInfo_t; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} + { + XPLMObjectLoaded_f + + You provide this callback when loading an object asynchronously; it will be + called once the object is loaded. Your refcon is passed back. The object + ref passed in is the newly loaded object (ready for use) or NULL if an + error occured. + + If your plugin is disabled, this callback will be delivered as soon as the + plugin is re-enabled. If your plugin is unloaded before this callback is + ever called, the SDK will release the object handle for you. + } +TYPE + XPLMObjectLoaded_f = PROCEDURE( + inObject : XPLMObjectRef; + inRefcon : pointer); cdecl; +{$ENDIF XPLM210} + +{$IFDEF XPLM200} + { + XPLMLoadObject + + This routine loads an OBJ file and returns a handle to it. If X-Plane has + already loaded the object, the handle to the existing object is returned. + Do not assume you will get the same handle back twice, but do make sure to + call unload once for every load to avoid "leaking" objects. The object will + be purged from memory when no plugins and no scenery are using it. + + The path for the object must be relative to the X-System base folder. If + the path is in the root of the X-System folder you may need to prepend ./ + to it; loading objects in the root of the X-System folder is STRONGLY + discouraged - your plugin should not dump art resources in the root folder! + + XPLMLoadObject will return NULL if the object cannot be loaded (either + because it is not found or the file is misformatted). This routine will + load any object that can be used in the X-Plane scenery system. + + It is important that the datarefs an object uses for animation already be + loaded before you load the object. For this reason it may be necessary to + defer object loading until the sim has fully started. + } + FUNCTION XPLMLoadObject( + inPath : XPLMString) : XPLMObjectRef; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM210} + { + XPLMLoadObjectAsync + + This routine loads an object asynchronously; control is returned to you + immediately while X-Plane loads the object. The sim will not stop flying + while the object loads. For large objects, it may be several seconds before + the load finishes. + + You provide a callback function that is called once the load has completed. + Note that if the object cannot be loaded, you will not find out until the + callback function is called with a NULL object handle. + + There is no way to cancel an asynchronous object load; you must wait for + the load to complete and then release the object if it is no longer + desired. + } + PROCEDURE XPLMLoadObjectAsync( + inPath : XPLMString; + inCallback : XPLMObjectLoaded_f; + inRefcon : pointer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM210} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMDrawObjects + + __Deprecation Warning__: use XPLMInstancing to draw 3-d objects by creating + instances, rather than these APIs from draw callbacks. + + XPLMDrawObjects draws an object from an OBJ file one or more times. You + pass in the object and an array of XPLMDrawInfo_t structs, one for each + place you would like the object to be drawn. + + X-Plane will attempt to cull the objects based on LOD and visibility, and + will pick the appropriate LOD. + + Lighting is a boolean; pass 1 to show the night version of object with + night-only lights lit up. Pass 0 to show the daytime version of the object. + + earth_relative controls the coordinate system. If this is 1, the rotations + you specify are applied to the object after its coordinate system is + transformed from local to earth-relative coordinates -- that is, an object + with no rotations will point toward true north and the Y axis will be up + against gravity. If this is 0, the object is drawn with your rotations from + local coordanates -- that is, an object with no rotations is drawn pointing + down the -Z axis and the Y axis of the object matches the local coordinate + Y axis. + } + PROCEDURE XPLMDrawObjects( + inObject : XPLMObjectRef; + inCount : Integer; + inLocations : PXPLMDrawInfo_t; + lighting : Integer; + earth_relative : Integer); + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM200} + { + XPLMUnloadObject + + This routine marks an object as no longer being used by your plugin. + Objects are reference counted: once no plugins are using an object, it is + purged from memory. Make sure to call XPLMUnloadObject once for each + successful call to XPLMLoadObject. + } + PROCEDURE XPLMUnloadObject( + inObject : XPLMObjectRef); + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * Library Access + ___________________________________________________________________________} +{ + The library access routines allow you to locate scenery objects via the + X-Plane library system. Right now library access is only provided for + objects, allowing plugin-drawn objects to be extended using the library + system. +} + + + { + XPLMLibraryEnumerator_f + + An XPLMLibraryEnumerator_f is a callback you provide that is called once + for each library element that is located. The returned paths will be + relative to the X-System folder. + } +TYPE + XPLMLibraryEnumerator_f = PROCEDURE( + inFilePath : XPLMString; + inRef : pointer); cdecl; + + { + XPLMLookupObjects + + This routine looks up a virtual path in the library system and returns all + matching elements. You provide a callback - one virtual path may match many + objects in the library. XPLMLookupObjects returns the number of objects + found. + + The latitude and longitude parameters specify the location the object will + be used. The library system allows for scenery packages to only provide + objects to certain local locations. Only objects that are allowed at the + latitude/longitude you provide will be returned. + } + FUNCTION XPLMLookupObjects( + inPath : XPLMString; + inLatitude : Single; + inLongitude : Single; + enumerator : XPLMLibraryEnumerator_f; + ref : pointer) : Integer; + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMUtilities.pas b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMUtilities.pas new file mode 100644 index 0000000..121e28b --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/Delphi/XPLM/XPLMUtilities.pas @@ -0,0 +1,951 @@ +{ + Copyright 2005-2012 Sandy Barbour and Ben Supnik All rights reserved. See + license.txt for usage. X-Plane SDK Version: 2.1.1 +} + +UNIT XPLMUtilities; +INTERFACE + +USES + XPLMDefs; + {$A4} +{___________________________________________________________________________ + * FILE UTILITIES + ___________________________________________________________________________} +{ + The XPLMUtilities file APIs provide some basic file and path functions for + use with X-Plane. + + Directory Separators + -------------------- + + The XPLM has two modes it can work in: + + * X-Plane native paths: all paths are UTF8 strings, using the unix forward + slash (/) as the directory separating character. In native path mode, + you use the same path format for all three operating systems. + + * Legacy OS paths: the directroy separator is \ for Windows, : for OS X, + and / for Linux; OS paths are encoded in MacRoman for OS X using legacy + HFS conventions, use the application code page for multi-byte encoding + on Unix using DOS path conventions, and use UTF-8 for Linux. + + While legacy OS paths are the default, we strongly encourage you to opt in + to native paths using the XPLMEnableFeature API. + + * All OS X plugins should enable native paths all of the time; if you do + not do this, you will have to convert all paths back from HFS to Unix + (and deal with MacRoman) - code written using native paths and the C + file APIs "just works" on OS X. + + * For Linux plugins, there is no difference between the two encodings. + + * Windows plugins will need to convert the UTF8 file paths to UTF16 for + use with the "wide" APIs. While it might seem tempting to stick with + legacy OS paths (and just use the "ANSI" Windows APIs), X-Plane is fully + unicode-capable, and will often be installed in paths where the user's + directories have no ACP encoding. + + Full and Relative Paths + ----------------------- + + Some of these APIs use full paths, but others use paths relative to the + user's X-Plane installation. This is documented on a per-API basis. +} + + +{$IFDEF XPLM200} + { + XPLMDataFileType + + These enums define types of data files you can load or unload using the + SDK. + } +TYPE + XPLMDataFileType = ( + { A situation (.sit) file, which starts off a flight in a given } + { configuration. } + xplm_DataFile_Situation = 1 + + { A situation movie (.smo) file, which replays a past flight. } + ,xplm_DataFile_ReplayMovie = 2 + + ); + PXPLMDataFileType = ^XPLMDataFileType; +{$ENDIF XPLM200} + + { + XPLMGetSystemPath + + This function returns the full path to the X-System folder. Note that this + is a directory path, so it ends in a trailing : or /. + + The buffer you pass should be at least 512 characters long. The path is + returned using the current native or OS path conventions. + } + PROCEDURE XPLMGetSystemPath( + outSystemPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetPrefsPath + + This routine returns a full path to a file that is within X-Plane's + preferences directory. (You should remove the file name back to the last + directory separator to get the preferences directory using + XPLMExtractFileAndPath.) + + The buffer you pass should be at least 512 characters long. The path is + returned using the current native or OS path conventions. + } + PROCEDURE XPLMGetPrefsPath( + outPrefsPath : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetDirectorySeparator + + This routine returns a string with one char and a null terminator that is + the directory separator for the current platform. This allows you to write + code that concatinates directory paths without having to #ifdef for + platform. The character returned will reflect the current file path mode. + } + FUNCTION XPLMGetDirectorySeparator: XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMExtractFileAndPath + + Given a full path to a file, this routine separates the path from the file. + If the path is a partial directory (e.g. ends in : or \) the trailing + directory separator is removed. This routine works in-place; a pointer to + the file part of the buffer is returned; the original buffer still starts + with the path and is null terminated with no trailing separator. + } + FUNCTION XPLMExtractFileAndPath( + inFullPath : XPLMString) : XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMGetDirectoryContents + + This routine returns a list of files in a directory (specified by a full + path, no trailing : or \). The output is returned as a list of NULL + terminated strings. An index array (if specified) is filled with pointers + into the strings. The last file is indicated by a zero-length string (and + NULL in the indices). This routine will return 1 if you had capacity for + all files or 0 if you did not. You can also skip a given number of files. + + * inDirectoryPath - a null terminated C string containing the full path to + the directory with no trailing directory char. + + * inFirstReturn - the zero-based index of the first file in the directory + to return. (Usually zero to fetch all in one pass.) + + * outFileNames - a buffer to receive a series of sequential null + terminated C-string file names. A zero-length C string will be appended + to the very end. + + * inFileNameBufSize - the size of the file name buffer in bytes. + + * outIndices - a pointer to an array of character pointers that will + become an index into the directory. The last file will be followed by a + NULL value. Pass NULL if you do not want indexing information. + + * inIndexCount - the max size of the index in entries. + + * outTotalFiles - if not NULL, this is filled in with the number of files + in the directory. + + * outReturnedFiles - if not NULL, the number of files returned by this + iteration. + + Return value: 1 if all info could be returned, 0 if there was a buffer + overrun. + + WARNING: Before X-Plane 7 this routine did not properly iterate through + directories. If X-Plane + 6 compatibility is needed, use your own code to iterate directories. + } + FUNCTION XPLMGetDirectoryContents( + inDirectoryPath : XPLMString; + inFirstReturn : Integer; + outFileNames : XPLMString; + inFileNameBufSize : Integer; + outIndices : PXPLMString; { Can be nil } + inIndexCount : Integer; + outTotalFiles : PInteger; { Can be nil } + outReturnedFiles : PInteger) : Integer; { Can be nil } + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMLoadDataFile + + Loads a data file of a given type. Paths must be relative to the X-System + folder. To clear the replay, pass a NULL file name (this is only valid with + replay movies, not sit files). + } + FUNCTION XPLMLoadDataFile( + inFileType : XPLMDataFileType; + inFilePath : XPLMString) : Integer; { Can be nil } + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMSaveDataFile + + Saves the current situation or replay; paths are relative to the X-System + folder. + } + FUNCTION XPLMSaveDataFile( + inFileType : XPLMDataFileType; + inFilePath : XPLMString) : Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{___________________________________________________________________________ + * X-PLANE MISC + ___________________________________________________________________________} + + { + XPLMHostApplicationID + + While the plug-in SDK is only accessible to plugins running inside X-Plane, + the original authors considered extending the API to other applications + that shared basic infrastructure with X-Plane. These enumerations are + hold-overs from that original roadmap; all values other than X-Plane are + deprecated. Your plugin should never need this enumeration. + } +TYPE + XPLMHostApplicationID = ( + xplm_Host_Unknown = 0 + + ,xplm_Host_XPlane = 1 + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_PlaneMaker = 2 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_WorldMaker = 3 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_Briefer = 4 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_PartMaker = 5 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_YoungsMod = 6 +{$ENDIF XPLM_DEPRECATED} + +{$IFDEF XPLM_DEPRECATED} + ,xplm_Host_XAuto = 7 +{$ENDIF XPLM_DEPRECATED} + + ); + PXPLMHostApplicationID = ^XPLMHostApplicationID; + + { + XPLMLanguageCode + + These enums define what language the sim is running in. These enumerations + do not imply that the sim can or does run in all of these languages; they + simply provide a known encoding in the event that a given sim version is + localized to a certain language. + } + XPLMLanguageCode = ( + xplm_Language_Unknown = 0 + + ,xplm_Language_English = 1 + + ,xplm_Language_French = 2 + + ,xplm_Language_German = 3 + + ,xplm_Language_Italian = 4 + + ,xplm_Language_Spanish = 5 + + ,xplm_Language_Korean = 6 + +{$IFDEF XPLM200} + ,xplm_Language_Russian = 7 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + ,xplm_Language_Greek = 8 +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + ,xplm_Language_Japanese = 9 +{$ENDIF XPLM200} + +{$IFDEF XPLM300} + ,xplm_Language_Chinese = 10 +{$ENDIF XPLM300} + + ); + PXPLMLanguageCode = ^XPLMLanguageCode; + +{$IFDEF XPLM200} + { + XPLMError_f + + An XPLM error callback is a function that you provide to receive debugging + information from the plugin SDK. See XPLMSetErrorCallback for more + information. NOTE: for the sake of debugging, your error callback will be + called even if your plugin is not enabled, allowing you to receive debug + info in your XPluginStart and XPluginStop callbacks. To avoid causing logic + errors in the management code, do not call any other plugin routines from + your error callback - it is only meant for catching errors in the + debugging. + } +TYPE + XPLMError_f = PROCEDURE( + inMessage : XPLMString); cdecl; +{$ENDIF XPLM200} + +{$IFDEF XPLM_DEPRECATED} + { + XPLMInitialized + + Deprecated: This function returns 1 if X-Plane has properly initialized the + plug-in system. If this routine returns 0, many XPLM functions will not + work. + + NOTE: because plugins are always called from within the XPLM, there is no + need to check for initialization; it will always return 1. This routine is + deprecated - you do not need to check it before continuing within your + plugin. + } + FUNCTION XPLMInitialized: Integer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM_DEPRECATED} + + { + XPLMGetVersions + + This routine returns the revision of both X-Plane and the XPLM DLL. All + versions are three-digit decimal numbers (e.g. 606 for version 6.06 of + X-Plane); the current revision of the XPLM is 200 (2.00). This routine also + returns the host ID of the app running us. + + The most common use of this routine is to special-case around X-Plane + version-specific behavior. + } + PROCEDURE XPLMGetVersions( + outXPlaneVersion : PInteger; + outXPLMVersion : PInteger; + outHostID : PXPLMHostApplicationID); + cdecl; external XPLM_DLL; + + { + XPLMGetLanguage + + This routine returns the langauge the sim is running in. + } + FUNCTION XPLMGetLanguage: XPLMLanguageCode; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} + { + XPLMFindSymbol + + This routine will attempt to find the symbol passed in the inString + parameter. If the symbol is found a pointer the function is returned, + othewise the function will return NULL. + + You can use XPLMFindSymbol to utilize newer SDK API features without + requiring newer versions of the SDK (and X-Plane) as your minimum X-Plane + version as follows: + + * Define the XPLMnnn macro to the minimum required XPLM version you will + ship with (e.g. XPLM210 for X-Plane 10 compatibility). + + * Use XPLMGetVersions and XPLMFindSymbol to detect that the host sim is + new enough to use new functions and resolve function pointers. + + * Conditionally use the new functions if and only if XPLMFindSymbol only + returns a non- NULL pointer. + + Warning: you should always check the XPLM API version as well as the + results of XPLMFindSymbol to determine if funtionality is safe to use. + + To use functionality via XPLMFindSymbol you will need to copy your own + definitions of the X-Plane API prototypes and cast the returned pointer to + the correct type. + } + FUNCTION XPLMFindSymbol( + inString : XPLMString) : pointer; + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + +{$IFDEF XPLM200} + { + XPLMSetErrorCallback + + XPLMSetErrorCallback installs an error-reporting callback for your plugin. + Normally the plugin system performs minimum diagnostics to maximize + performance. When you install an error callback, you will receive calls due + to certain plugin errors, such as passing bad parameters or incorrect data. + + Important: the error callback determines *programming* errors, e.g. bad API + parameters. Every error that is returned by the error callback represents a + mistake in your plugin that you should fix. Error callbacks are not used to + report expected run-time problems (e.g. disk I/O errors). + + The intention is for you to install the error callback during debug + sections and put a break-point inside your callback. This will cause you to + break into the debugger from within the SDK at the point in your plugin + where you made an illegal call. + + Installing an error callback may activate error checking code that would + not normally run, and this may adversely affect performance, so do not + leave error callbacks installed in shipping plugins. Since the only useful + response to an error is to change code, error callbacks are not useful "in + the field". + } + PROCEDURE XPLMSetErrorCallback( + inCallback : XPLMError_f); + cdecl; external XPLM_DLL; +{$ENDIF XPLM200} + + { + XPLMDebugString + + This routine outputs a C-style string to the Log.txt file. The file is + immediately flushed so you will not lose data. (This does cause a + performance penalty.) + + Please do *not* leave routine diagnostic logging enabled in your shipping + plugin. The X-Plane Log file is shared by X-Plane and every plugin in the + system, and plugins that (when functioning normally) print verbose log + output make it difficult for developers to find error conditions from other + parts of the system. + } + PROCEDURE XPLMDebugString( + inString : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMSpeakString + + This function displays the string in a translucent overlay over the current + display and also speaks the string if text-to-speech is enabled. The string + is spoken asynchronously, this function returns immediately. This function + may not speak or print depending on user preferences. + } + PROCEDURE XPLMSpeakString( + inString : XPLMString); + cdecl; external XPLM_DLL; + + { + XPLMGetVirtualKeyDescription + + Given a virtual key code (as defined in XPLMDefs.h) this routine returns a + human-readable string describing the character. This routine is provided + for showing users what keyboard mappings they have set up. The string may + read 'unknown' or be a blank or NULL string if the virtual key is unknown. + } + FUNCTION XPLMGetVirtualKeyDescription( + inVirtualKey : XPLMChar) : XPLMString; + cdecl; external XPLM_DLL; + + { + XPLMReloadScenery + + XPLMReloadScenery reloads the current set of scenery. You can use this + function in two typical ways: simply call it to reload the scenery, picking + up any new installed scenery, .env files, etc. from disk. Or, change the + lat/ref and lon/ref data refs and then call this function to shift the + scenery environment. This routine is equivalent to picking "reload + scenery" from the developer menu. + } + PROCEDURE XPLMReloadScenery; + cdecl; external XPLM_DLL; + +{$IFDEF XPLM200} +{___________________________________________________________________________ + * X-PLANE COMMAND MANAGEMENT + ___________________________________________________________________________} +{ + The command management APIs let plugins interact with the command-system in + X-Plane, the abstraction behind keyboard presses and joystick buttons. This + API lets you create new commands and modify the behavior (or get + notification) of existing ones. + + X-Plane Command Phases + ---------------------- + + X-Plane commands are not instantaneous; they operate over a duration. + (Think of a joystick button press - you can press, hold down, and then + release the joystick button; X-Plane commands model this entire process.) + + An X-Plane command consists of three phases: a beginning, continuous + repetition, and an ending. The command may be repeated zero times in its + duration, followed by one command ending. Command begin and end messges are + balanced, but a command may be bound to more than one event source (e.g. a + keyboard key and a joystick button), in which case you may receive a second + begin during before any end). + + When you issue commands in the plugin system, you *must* balance every call + to XPLMCommandBegin with a call to XPLMCommandEnd with the same command + reference. + + Command Behavior Modification + ----------------------------- + + You can register a callback to handle a command either before or after + X-Plane does; if you receive the command before X-Plane you have the option + to either let X-Plane handle the command or hide the command from X-Plane. + This lets plugins both augment commands and replace them. + + If you register for an existing command, be sure that you are *consistent* + in letting X-Plane handle or not handle the command; you are responsible + for passing a *balanced* number of begin and end messages to X-Plane. (E.g. + it is not legal to pass all the begin messages to X-Plane but hide all the + end messages). +} + + + { + XPLMCommandPhase + + The phases of a command. + } +TYPE + XPLMCommandPhase = ( + { The command is being started. } + xplm_CommandBegin = 0 + + { The command is continuing to execute. } + ,xplm_CommandContinue = 1 + + { The command has ended. } + ,xplm_CommandEnd = 2 + + ); + PXPLMCommandPhase = ^XPLMCommandPhase; + + { + XPLMCommandRef + + A command ref is an opaque identifier for an X-Plane command. Command + references stay the same for the life of your plugin but not between + executions of X-Plane. Command refs are used to execute commands, create + commands, and create callbacks for particular commands. + + Note that a command is not "owned" by a particular plugin. Since many + plugins may participate in a command's execution, the command does not go + away if the plugin that created it is unloaded. + } + XPLMCommandRef = pointer; + PXPLMCommandRef = ^XPLMCommandRef; + + { + XPLMCommandCallback_f + + A command callback is a function in your plugin that is called when a + command is pressed. Your callback receives the command reference for the + particular command, the phase of the command that is executing, and a + reference pointer that you specify when registering the callback. + + Your command handler should return 1 to let processing of the command + continue to other plugins and X-Plane, or 0 to halt processing, potentially + bypassing X-Plane code. + } + XPLMCommandCallback_f = FUNCTION( + inCommand : XPLMCommandRef; + inPhase : XPLMCommandPhase; + inRefcon : pointer) : Integer; cdecl; + + { + XPLMFindCommand + + XPLMFindCommand looks up a command by name, and returns its command + reference or NULL if the command does not exist. + } + FUNCTION XPLMFindCommand( + inName : XPLMString) : XPLMCommandRef; + cdecl; external XPLM_DLL; + + { + XPLMCommandBegin + + XPLMCommandBegin starts the execution of a command, specified by its + command reference. The command is "held down" until XPLMCommandEnd is + called. You must balance each XPLMCommandBegin call with an XPLMCommandEnd + call. + } + PROCEDURE XPLMCommandBegin( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCommandEnd + + XPLMCommandEnd ends the execution of a given command that was started with + XPLMCommandBegin. You must not issue XPLMCommandEnd for a command you did + not begin. + } + PROCEDURE XPLMCommandEnd( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCommandOnce + + This executes a given command momentarily, that is, the command begins and + ends immediately. This is the equivalent of calling XPLMCommandBegin() and + XPLMCommandEnd() back ot back. + } + PROCEDURE XPLMCommandOnce( + inCommand : XPLMCommandRef); + cdecl; external XPLM_DLL; + + { + XPLMCreateCommand + + XPLMCreateCommand creates a new command for a given string. If the command + already exists, the existing command reference is returned. The description + may appear in user interface contexts, such as the joystick configuration + screen. + } + FUNCTION XPLMCreateCommand( + inName : XPLMString; + inDescription : XPLMString) : XPLMCommandRef; + cdecl; external XPLM_DLL; + + { + XPLMRegisterCommandHandler + + XPLMRegisterCommandHandler registers a callback to be called when a command + is executed. You provide a callback with a reference pointer. + + If inBefore is true, your command handler callback will be executed before + X-Plane executes the command, and returning 0 from your callback will + disable X-Plane's processing of the command. If inBefore is false, your + callback will run after X-Plane. (You can register a single callback both + before and after a command.) + } + PROCEDURE XPLMRegisterCommandHandler( + inComand : XPLMCommandRef; + inHandler : XPLMCommandCallback_f; + inBefore : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + + { + XPLMUnregisterCommandHandler + + XPLMUnregisterCommandHandler removes a command callback registered with + XPLMRegisterCommandHandler. + } + PROCEDURE XPLMUnregisterCommandHandler( + inComand : XPLMCommandRef; + inHandler : XPLMCommandCallback_f; + inBefore : Integer; + inRefcon : pointer); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM200} +{$IFDEF XPLM_DEPRECATED} +{___________________________________________________________________________ + * X-PLANE USER INTERACTION + ___________________________________________________________________________} +{ + WARNING: The legacy user interaction API is deprecated; while it was the + only way to run commands in X-Plane 6,7 and 8, it is obsolete, and was + replaced by the command system API in X-Plane 9. You should not use this + API; replace any of the calls below with XPLMCommand invocations based on + persistent command strings. The documentation that follows is for historic + reference only. + + The legacy user interaction APIs let you simulate commands the user can do + with a joystick, keyboard etc. Note that it is generally safer for future + compatibility to use one of these commands than to manipulate the + underlying sim data. +} + + + { + XPLMCommandKeyID + + These enums represent all the keystrokes available within X-Plane. They can + be sent to X-Plane directly. For example, you can reverse thrust using + these enumerations. + } +TYPE + XPLMCommandKeyID = ( + xplm_key_pause=0, + xplm_key_revthrust, + xplm_key_jettison, + xplm_key_brakesreg, + xplm_key_brakesmax, + xplm_key_gear, + xplm_key_timedn, + xplm_key_timeup, + xplm_key_fadec, + xplm_key_otto_dis, + xplm_key_otto_atr, + xplm_key_otto_asi, + xplm_key_otto_hdg, + xplm_key_otto_gps, + xplm_key_otto_lev, + xplm_key_otto_hnav, + xplm_key_otto_alt, + xplm_key_otto_vvi, + xplm_key_otto_vnav, + xplm_key_otto_nav1, + xplm_key_otto_nav2, + xplm_key_targ_dn, + xplm_key_targ_up, + xplm_key_hdgdn, + xplm_key_hdgup, + xplm_key_barodn, + xplm_key_baroup, + xplm_key_obs1dn, + xplm_key_obs1up, + xplm_key_obs2dn, + xplm_key_obs2up, + xplm_key_com1_1, + xplm_key_com1_2, + xplm_key_com1_3, + xplm_key_com1_4, + xplm_key_nav1_1, + xplm_key_nav1_2, + xplm_key_nav1_3, + xplm_key_nav1_4, + xplm_key_com2_1, + xplm_key_com2_2, + xplm_key_com2_3, + xplm_key_com2_4, + xplm_key_nav2_1, + xplm_key_nav2_2, + xplm_key_nav2_3, + xplm_key_nav2_4, + xplm_key_adf_1, + xplm_key_adf_2, + xplm_key_adf_3, + xplm_key_adf_4, + xplm_key_adf_5, + xplm_key_adf_6, + xplm_key_transpon_1, + xplm_key_transpon_2, + xplm_key_transpon_3, + xplm_key_transpon_4, + xplm_key_transpon_5, + xplm_key_transpon_6, + xplm_key_transpon_7, + xplm_key_transpon_8, + xplm_key_flapsup, + xplm_key_flapsdn, + xplm_key_cheatoff, + xplm_key_cheaton, + xplm_key_sbrkoff, + xplm_key_sbrkon, + xplm_key_ailtrimL, + xplm_key_ailtrimR, + xplm_key_rudtrimL, + xplm_key_rudtrimR, + xplm_key_elvtrimD, + xplm_key_elvtrimU, + xplm_key_forward, + xplm_key_down, + xplm_key_left, + xplm_key_right, + xplm_key_back, + xplm_key_tower, + xplm_key_runway, + xplm_key_chase, + xplm_key_free1, + xplm_key_free2, + xplm_key_spot, + xplm_key_fullscrn1, + xplm_key_fullscrn2, + xplm_key_tanspan, + xplm_key_smoke, + xplm_key_map, + xplm_key_zoomin, + xplm_key_zoomout, + xplm_key_cycledump, + xplm_key_replay, + xplm_key_tranID, + xplm_key_max + ); + PXPLMCommandKeyID = ^XPLMCommandKeyID; + + { + XPLMCommandButtonID + + These are enumerations for all of the things you can do with a joystick + button in X-Plane. They currently match the buttons menu in the equipment + setup dialog, but these enums will be stable even if they change in + X-Plane. + } + XPLMCommandButtonID = ( + xplm_joy_nothing=0, + xplm_joy_start_all, + xplm_joy_start_0, + xplm_joy_start_1, + xplm_joy_start_2, + xplm_joy_start_3, + xplm_joy_start_4, + xplm_joy_start_5, + xplm_joy_start_6, + xplm_joy_start_7, + xplm_joy_throt_up, + xplm_joy_throt_dn, + xplm_joy_prop_up, + xplm_joy_prop_dn, + xplm_joy_mixt_up, + xplm_joy_mixt_dn, + xplm_joy_carb_tog, + xplm_joy_carb_on, + xplm_joy_carb_off, + xplm_joy_trev, + xplm_joy_trm_up, + xplm_joy_trm_dn, + xplm_joy_rot_trm_up, + xplm_joy_rot_trm_dn, + xplm_joy_rud_lft, + xplm_joy_rud_cntr, + xplm_joy_rud_rgt, + xplm_joy_ail_lft, + xplm_joy_ail_cntr, + xplm_joy_ail_rgt, + xplm_joy_B_rud_lft, + xplm_joy_B_rud_rgt, + xplm_joy_look_up, + xplm_joy_look_dn, + xplm_joy_look_lft, + xplm_joy_look_rgt, + xplm_joy_glance_l, + xplm_joy_glance_r, + xplm_joy_v_fnh, + xplm_joy_v_fwh, + xplm_joy_v_tra, + xplm_joy_v_twr, + xplm_joy_v_run, + xplm_joy_v_cha, + xplm_joy_v_fr1, + xplm_joy_v_fr2, + xplm_joy_v_spo, + xplm_joy_flapsup, + xplm_joy_flapsdn, + xplm_joy_vctswpfwd, + xplm_joy_vctswpaft, + xplm_joy_gear_tog, + xplm_joy_gear_up, + xplm_joy_gear_down, + xplm_joy_lft_brake, + xplm_joy_rgt_brake, + xplm_joy_brakesREG, + xplm_joy_brakesMAX, + xplm_joy_speedbrake, + xplm_joy_ott_dis, + xplm_joy_ott_atr, + xplm_joy_ott_asi, + xplm_joy_ott_hdg, + xplm_joy_ott_alt, + xplm_joy_ott_vvi, + xplm_joy_tim_start, + xplm_joy_tim_reset, + xplm_joy_ecam_up, + xplm_joy_ecam_dn, + xplm_joy_fadec, + xplm_joy_yaw_damp, + xplm_joy_art_stab, + xplm_joy_chute, + xplm_joy_JATO, + xplm_joy_arrest, + xplm_joy_jettison, + xplm_joy_fuel_dump, + xplm_joy_puffsmoke, + xplm_joy_prerotate, + xplm_joy_UL_prerot, + xplm_joy_UL_collec, + xplm_joy_TOGA, + xplm_joy_shutdown, + xplm_joy_con_atc, + xplm_joy_fail_now, + xplm_joy_pause, + xplm_joy_rock_up, + xplm_joy_rock_dn, + xplm_joy_rock_lft, + xplm_joy_rock_rgt, + xplm_joy_rock_for, + xplm_joy_rock_aft, + xplm_joy_idle_hilo, + xplm_joy_lanlights, + xplm_joy_max + ); + PXPLMCommandButtonID = ^XPLMCommandButtonID; + + { + XPLMSimulateKeyPress + + This function simulates a key being pressed for X-Plane. The keystroke goes + directly to X-Plane; it is never sent to any plug-ins. However, since this + is a raw key stroke it may be mapped by the keys file or enter text into a + field. + + Deprecated: use XPLMCommandOnce + } + PROCEDURE XPLMSimulateKeyPress( + inKeyType : Integer; + inKey : Integer); + cdecl; external XPLM_DLL; + + { + XPLMCommandKeyStroke + + This routine simulates a command-key stroke. However, the keys are done by + function, not by actual letter, so this function works even if the user has + remapped their keyboard. Examples of things you might do with this include + pausing the simulator. + + Deprecated: use XPLMCommandOnce + } + PROCEDURE XPLMCommandKeyStroke( + inKey : XPLMCommandKeyID); + cdecl; external XPLM_DLL; + + { + XPLMCommandButtonPress + + This function simulates any of the actions that might be taken by pressing + a joystick button. However, this lets you call the command directly rather + than have to know which button is mapped where. Important: you must release + each button you press. The APIs are separate so that you can 'hold down' a + button for a fixed amount of time. + + Deprecated: use XPLMCommandBegin. + } + PROCEDURE XPLMCommandButtonPress( + inButton : XPLMCommandButtonID); + cdecl; external XPLM_DLL; + + { + XPLMCommandButtonRelease + + This function simulates any of the actions that might be taken by pressing + a joystick button. See XPLMCommandButtonPress. + + Deprecated: use XPLMCommandEnd. + } + PROCEDURE XPLMCommandButtonRelease( + inButton : XPLMCommandButtonID); + cdecl; external XPLM_DLL; + +{$ENDIF XPLM_DEPRECATED} + +IMPLEMENTATION + +END. diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Libraries/Mac/XPLM.framework/XPLM b/XPLPro_Plugin_Source/SDK/SDKold/Libraries/Mac/XPLM.framework/XPLM new file mode 100644 index 0000000000000000000000000000000000000000..99a7a721c0b977b5969e82367b7ef6299fccbdc7 GIT binary patch literal 566176 zcmeEvdwf*I`S%905P`7a5)DcqO4LLU5+#}#7P2G@XJsP@qO_U@MG%xrgk6cnNH9b> z9=D=ZpAwq9c7vJqs1QVbU%fDSh~XPY_a6w_b|Mco`~x~k0mw_&$KG|dgAH$ z>!3gf1v)6uL4ghmbWos!0v#0Spg;!&Iw;UVfes3EP@sbX9Te!GKnDdnD9}NH4hnQo zpo0P(6zHHp2L(DP&_RI?3UpAQg905C=%7Fc1v)6uL4ghmbWos!0v#0Spg;!&Iw;UV zfes3EP@sbX9Te!GKnDdnD9}NH4hnQopo0P(6zHHp2L(DP&_RI?3UpB5|1kwV{Nbxp zIQSofga4K;czWY0jk8!PExlw({TS|Ku@o2I;GA-UjB5Q;j#~nv|IDxzaeR2G0RM`M zJ=04)%CEw$;Ux?*-wjpp7>;d8&Omu|u()`E$9vm?NK{+=60TQpR+{KB9F1w536FK= zpMqCBbNcL(>GNf{HGZoms@#7DE%?W<=~WS@;djThX~ok^r%f;M6nk#Htu21;$qHU+ zyvojSD|jk8@>^UyZQk4kEd*=}ul_a#ufoj1a4Y&nASn;vE%3~rHTMoPzAd~-(-geX zeN=*QI1HvOuEoXPxeI5_y}fwW+!^zbs4cve_b7O`oTDHx+!jU{HeK>v9TF557dUQk zM7;^~Tb>!$CQLr&0~VHl#l>@H7caPX&TaE%7ngYEpAlX-y#?@?Km14jC=!a9eoJR`6!udN%y>On50Ku^5hq$NuGR1#iwgHo`1V@eJ?WX{Xh9 z>I14B^2|I8N5eClCj#+wzH8kcRVKW0v!gS7cD}p)R?n>w@TcLI^030MznO&Lv+)V> zn=@zL+%Uwp{E}zFTcyCtWYPFVMay@^#kVbJkt(OR?-4`gSbkx+#MW}EEj;qEhNrmL z?YeH9v%nRWp?))Eo>{wac$f?F9Q z0KL36M&jK7HxHd7>HQdsz~Dgam@cj{#&RcahY_nfS^VEvEZq?|0T2I1A;9NT`1>Qx zbuza7pH+Y9WLe(Ms|ygvaytD`GOzR%`#*oTa8&Wc**%O@#3e9&w{9R%56flYFyrvY z3u|WLk$D+0D-WFclx5hYdlz`7&l%>Pb=&+~=ifVQOqdJ{hUL$jKYh$R?_4nEta)>z z2z2B0`3n%UV3?y#8h~XvQ}9H}k*yVTwsOXoOrJZ}-9CKv&V*ai3T`$+XNBu1DVaTM znnZrm^!fM9LX)>&NIMB-Ju;%p>%1D>1Lb)a%pW#;)@^*I4IVr+bLj2&!Yk7gqn3IP z#4z7Fy(0C{(PkE;wpcE~BirrM7)v9VDBTPRDRahh*@ z54Ue@g4;K~ujU(@r0KD#j?m)`fQ;f2R944LjvF159XCt@46VX`H;c9{{WsFM^ery^ zBTYZ%(oboIGvSymq3bbQFK0D8UFcZ@PbYf(@Wjxw(XBgIA9L6eEDY7T^}a zp}jiO<7bo;5EGmm>5WaLw@xz(S0f3EOmJ>NU{yF!j{xe>E9M;%H+@5Ji1Y-92CVm@ zB>n}gKVM4S1>P`$g&y zHflg%x!YnJxKsk3ARa-iD8dh0I5Sk##CXXjpnFn<{rlU2f~UAL$w)$+a_r-f!P|X3^A|NSS}{wG{fg)pBjk(a%a=2gW-N>=YC4q| zRV@vS<11<;&Qk$N^Vv6mrkcJ_^gEZt+R*H5jPabK8D&SrSmNNb{+$VOHh2;=V_bHo zzvAAMkY;n%20LZ?Tab^+mLO5zFJ8G!kyf(v4U=5@adNGGTzt+16(^1?xY?y|gy*~k zz4CqN2g|y+LYoRJ4|*>RUg_2kXcZe0w2A{qi0iw6<{6UOMA5f^zh;!+i-1>31 ze#)(XCPo5e{-)SVEaU>o19&G!B3HP*L6Yzv`|UZTk1@7?(S}UF?Be1)l7qcj(`!{N zZBP1HNwYsAQ?_QrzXWP)m76_7PH^nAv~XgS+7+vq@WTNH{( z5fn*C%7i3mW-}9HY5Ga6VsV>O=vaE;=1#IxcS6N7^%&5A1wSp4X4 zwR2GIJd5WFSxOWp*M%{$0TWhS795(CCrh5l651APH;dITRrH?Is@Rm)71vr#PY|gcAsML*d6*-hrZLL ze}~cmyiV+S48VQPx^i&Exh4a+^{)%`&kFQ!LX)OA^ngsa6X^=j^(61L86oP#n}h-) zbTYB|;`@KJWqY`^rp(OtDB}kQo`o_q!<4B(x-(PeSwaD2M5@AO z%ZdL9WlGLKnIV97M#_{($_!?K?NcVf#N`$fm%R3HX-%2Z_9*k0N6$)`(lBMJknYTs zd4NzrnXQ8qW&Uye43xP(%rlx+@lH9!g2gkkJ+`p{pdt<#8FjU^u+49oPtvD5i*27i zM}DI)8ew9T(hf!%G{4o*1*@S$I`oem`f;TS_*s?7AShIU>LS)?pXiCN!D+tu*BH#H z^Q5?ql59uC{V5^a(gPA5`!~a(J2j%%CJcub%}9QZX)E`7E;I6bl1# z4U8~QuVaA2N*9FPI!5{b%105} zO82ZI9B)H@J--LU+h|*_f-4iQ4HR6-6qb;+F9G<a+(s@5UkeBh+ncuL z+89q4moYvr*jd}w1a93-o#k@J#x0JIu}yKk24uut$cJjrupRavvn{qj71Q%EAz7TC0Z$$%<<^_U zxkyxC%-LC>-<1@|Pva)z_55*E{FJgVyPDnty{V>43}D&*^#1&dw2JRzJ-zXp;_WB( z^=c~Z!EWp0;8gQR&rcJJW!d@YT=vydQ2AW@Yj8BZsM^!Vr4Mvf1mfJf{Yk_%ZATVN zESA9UO5Y8YSF1hMS@T^Nqv=o~h22(}in?jlqzL{77V1B`YJcqH%Gu(!jsCaxwu%nf zw4AMOTYe*mfF`K(T&n5bWv-l!wuim}MXvRY_#EX}#Ek+5mA z?Mpr8!ju?13C=G_JyBR0y1yT2ghUwqesJj@inox}t$#1G>dD(~V(8-Sa5O!B2c638 zo;Xe4Ee;Jp0KGGFZ)UTwJuHbC1CjF-5W(c)1Gmrm2YB5!=LV3uliL^H4K+j%ZxYW{ z-W_-o>-HsAsNi0=&;F?Lp2QnWu`m8n1rJ~nb2XX?fC&wg@WjI^xI^=0U50J0cykPI zQo!7wso+Vs@ABR_BY+}HKQl+2Qv4#;oVuo<`;KC(P5RvXdTs+e4!ad-r4x`sIF=$_f6ryykecnv zy&*M^UGjX8+pp=P;|laUG5dKJ!UeCJKxd1~cOQ^h_jmQzO&ffkR{KL|t@=eX1`~{W z%{Lm8iX*m%`pOJ$)WbKTx0VyYG~3H(-yq%fM_)Pr?ix z#cL>jW`fJOKTbwh_<_b4gh36L;U-<)*V2z_>ClJnk3%Ehf3A2b8O$0NetQAq0;1tCnhfqtq@lRPv~Y1!jJJzsj7>431e~0d$ybo+A->fyFcfEK zxy9L@%R$u!V*yy?xVRVvl$SMFJOHsMF4Tu{SF+HG4M{E}_U=|Ae3TWVLG(7U`jv^* zXkbNbFzTVqPG0oLu_>5ww1ZG5?`RVtOj#g8+Ck~@2Tw<-3UOyeX)zOkP#>JH2=(gM z(I~|#lrR@)2c_5uN|;Qvk5Z`ebd=(M4y8lLM3k~kl=_<}O`4Fo7i3EC4l|0=YEO0| zkEEvW$oarl_^~$aU9GmUlh%1`iZ*SBR{L2eFps8h5{CgqT9v{Ez-W_P62aLjmw>Yz z`iIb^Tza!h|1sa!e^~8-PHc?a;U?YD#WFYVWQyD1`fwlf)R@PqmNjE7d+G zG2;F!VtfW5XC+45|Ckv60;sbQV_w= z1!s^g`bV*a$r6ek8j&L^E`4S3kJ)g<+L#OckM_i35v$*J|YHRJm1f}Hs&-mZbsQWw^YyD`2sd*U_ysAgORulKuP zGLpgK*A3R+idv}OnNZE(+=#du%#>|8;Qi) zO13L!zh|`DH#6JiTbSg`S(xBW*3yr8xK)Ol)efGt8+>ZD#du z2HaVM3k@y!Jm?x1J?a7D5vIN$UOc!;d;zskGZsK?IWG3V-<+Q!XBdkzL}4QNWxrJN z9q>yFsbm`3aY3o#ILxI$iM^g{fJmYKt>#+0j!1+X@b7M*j^+|IwPA~Z;V)MO$2Rkc3B0T-)-Cz7wm$$qifsO;dubd4R+D= z543GTSI$1r#bq14i(H#(GUVa}%o9QZ0?>?mWMGrH05t#`_Q~9gOt!~s-8sjks%*=z ztrY|1^u{cEeF9JucR*R9N&rUTDKyQrA~VO_?275)TG?<`xU?bN8^5ax)x!BV8H&s#5wWU(+j?e)ZFZV!%x zo!sr41I6+%LC7Eex>Dj|BQE8xUS+7J#47g+uum?dz5BrS>|B&HD| zfQcsuFt;%et-3L;u<|RwHl#3E>sTgCLF$Q#Os+8tR4MC%#@wLn)uMUK6mLFJ1R zEFN1_*XfOdP@u}w6w8pxj@5^7Z6|@^P?ej>DS@#`5|}I?JjZVV-|bJ%qneSBHZz^TD($Rg~&#H2cpzJ>(0`Fol^B}EKd zNEOSO=G3PTaq49mg}OHzr9Otj#S|n~W{aFDDc;@%Ia7ytdlcl9W_Y`}b4s#3SD{UV z`;dAXQo}GT?m`B0-OxUs5S~YbIjXlT9cJzg?r-4}arZBzsOoCuCsg|Hy#V0O<2r#a zD+Nx?YS2T>KoY#BAqql2+`(1-v4$YmYDLnOz&4Oi@dBPDpYazg7mJD}Y|4-0TgeDm z-9m?!lJ~$BIIc^ckupVmjw+)QDqI#5m)|K|o`40vhNGL*;v9J|p%dFu*r-iGdB|)opx)SCuRQ4E*F*U1zx_A-=pkSK@`t3r$cV>RY zT3n&E-w4)lBkUUsKv1kx0mQMEYy>Eq5h?m(Csq|<$T8g*7F(D&&QmhwCz7x{4 z+(`*u2#yKa@FjVWovERp`|N#?o#Kl8hhQwB{T2RTXDs8vj3>t*4j~Qkur+2j2lqs^ z`8PL4wYlWK6fqlqhm%M97^MA$PXtf+%wT8QD#Fs`(xziCL4uYuWV0_8_lqlrrt+ z`Q)>LR0y^EQil{ugObm_s{oZAhqSEpd9pWAm<^G_EJN~B@E{6#1?jLjAZ|y}urPa? zd7nXq-Vo8HAjUqA5LLW*Lt8GoUJ2k|QUFUSR)r)#%SGM(H&X1Q)?73&8W+h$I}|Qk zA!`&D^;Nk1EEiom9Q0}<#ag$?3ot^VO|FDf0|nY5KAI#u;T`!P*(Xwd9VEqvoJMge zxk&L5NJ{1z00KMKn3C&K=1-H7>oon<WR|HH`0OzX`Fmh|s=+Q5 zi%62lTPG4D$QL6IBR?(Flpvu-De}T>xm79{=4ksqOk4uuO+UuDqtE^YV6y+io>OxNLC*r{_2ocC#Ky7z z2MY9(6n#o6OsQ!F`qUv@nb5~(Xw^t!A<9r>hdTmeM=%VtZymyUwlrq~c2bSipo!6) z;tGtN$poVJTndu0B}kcql%+typGWC%O7zBi_i1b1;W1HZBu|q+|67e@y2+;IB*)%a z)p-ZZHZ>Kjvv-1pt0>TnyH+e3j-lG$rh`gTshsB6KLMpcu&0>WVCHOOE`$zT<}^ma zdRx(WxZ;H7ou_E%?}F6&28S`GubvO9^BC}KejZ%#Ouhyetd~Cl?gY3~;DQp z=Fb!dXLHr11mQe{OC1%VDc*j8{Nbd#!?@91@k8u_!TO}^U^+x+39Qod#>8?VD5a%& zkZ*V(U$#zglrbsWVcetX3r1ks!9NP^YjicnkpV-?s{m9%m|-jN&*qG7hHWucv9OMb z*Y$Xf#_EGioLf!jP$%`!@a7mPxV0sRmH{`VFK+~mK&rc7e5s-KB;v;t#v7#&L4Yal zVM@rcJ2-94wWfd%yj?Rx;yK3WCMPl69U6Rhc=(6nH3c$>AZ63lTt{VUIQK62tY42r zf#}i1ca_3-8l!+O^cM>Z>qO4n9f?&$)uMSwBGz`td!PYy;xW^PLEgB4Mu1}|bRZKn z$^;mzunQ;5lh`b&K$Iw^SOT+6&8MAE(?LKB+7XtC9+Q>bfcbPDNtd(1w)83114S);|1=r$asvW(2_ znVTJNlSUydogmLs%%dlN$h!Ni4R&V5e_kF-?VY(fGenZ**`C0HO2Nm$*vwGoUJwbn z+iv)AOGx|0%FciR%ffxTO;cQ0I*GWUD61VU_t|0XX}NnYH?`a-$&^;e$?_JM@~W{@ zh6FXN{jX3s>rT|j?xP{lmvs>a!M<%uK6bCgrqVFj#mFB5K&aH%OjUHQv)*e1siSQhVtc1H z#y!Yv2wdkHX`+S9{f?c=uy!(mD9Y#{2`CfCy2g<4{tk5v{13)U!W^31QcRnV&)!p| z+y~2#qDnbZVtWL-&Sl&;P@oSroNM$ku?1KRE6`_P|C#moxeDQM{}1-Tj)D}YJ|h*o z3(}ArbB-avX>P_@D)xO$I~6O`H)7@0Y;skxbQ6fG*e28n6&pr$lUcEC*M=)L3cKxC zu_k)@iG{!kT(pXqOrj$xH<7YwaxG)P5L0$vf}jb+Ip zE!?7W%#yFd>i1;;Ok1&Rz9Xth2gnGcJPp|pFL%!#ZBh8bzG!=|YzVXDcU4Uez|d23 zJxi{Plza@k)mUeiygK{LC1Ufoov#YT6ROnu1Z43r%Y0-}_%(7@6-aUm@yoS73=F)zomeu6 zm%C>vs&1^R*vl>HV81^N#WkVHQ{jDCNhUvzaCeE{&-q;^~7M?EA`Dp-x6IiRY+ zR9CnSC&*`r+paNT7A-JwGgqndvb^l}CI{VdfaMtNKqG9t!H&% zkuz9jzn$4@nY|0LXYN(%(fnq`ZLwGqDuqHB&8?9c+)rp=Fxf?f@F5{=EC_S!72*7D zy`)rTo-s7MdEPd##jvZ)*x?z#E(LHKY*#hBYgR0X0Q~oNA($b-_>ZA>wkK+_k)vg@ zKB<*{`+|aE5DGW?h|3A3MZbLtpxBcpq9=(@^Hr~9C-QP1-~B3gA#?X;?j1-WnU|{U zAn5qvj(-A-iwrBTL=;rnZq#(zsUnk%+i^>{~^In?Qt$QfM3fP&+59 zVk+vq!?D2j=8<3)>iGH#$*_MZzhI z^McWB?MD3+2VMk6*^Oo*$rT?nXYD=zCXriMsKsin zCg8sZQv>dp?tp72^@KyV_TMv6L1^D{Hh|gT2F%#51&J|GosYEG=w$&33UU^dc+;`o z1v`k6zkfq^#YIwF$8+%uQYy5ZVplV620!fe)`5a96rg&2SY2rP5y~{1R?%QEAVnp-q##KP9l>ICb7#uNOk_=M|mPeH*bpx0iS>^BY zh?;dEDnxGWku#-4P6VGg3f?iSHZwkh@q>AI3ENE$p;9zZUkDNzxenthBmTfJ00cZR zk6(C6y6|*H@+(vlE@5HO5I~b_Sbd-UIFJA?fpd^mj$gBg3#LiuN+KqJSyyHtiJU)W z2YVvCEE3L;gm2E=uIR|Ms}^w_*@$1Lzo!>MfyY8pvqS$8g|1Wtn8-p`#DW0dj-oCe zim_GxmT3FzFQF=oAcdgQ1~zwegs3B|EkE202|VB8sAUDp0|xvMZu6v5%8PD+mxF3B{A-HpZ4_?o~A^ z(7zAW2dxS|4@&F+5KyGEHxUMaZph5Pfc3}A)%mlqq>G zNkdK+2=D;_gpp(unvm)(VoDH$({=N4W$*fj;^^;Sd8*k<1XrL0w{LpAG?t3*Ku1VYN5zO# zi*4C%giykFu+)k*2b8292jt5a#aX=9VCKrX>J>(QMy_+GryJIWE~(%~z!Wm8x2Lfv z4HL~}cgh({4}`=UzoOqe&E%$P!2TU!9|G)(vid8$vt<5hh~Lck-1fa8}YUl^I_;q?QKB99Lnqlfi6~h z596nmmqT*X$1*m`Yh&yN85`y8%h;D?Y?QYjV^_%7h*zto`JRObom%z4us=t8dywhZ z^q#?A2fCy&Ns;MJ4RnE##S$zu-3eOt)sf^~f{s9!EBJb->1GDHOlNq2>0TJ-il`qp8N1D#q$WBC-6Lr=S4jK#PbfG4R}7lvjfjwJly>g7Up3An~lT85UrB= zx1p<{cb@1B=I=_$`t&tq{xZLuHHs6Es19S4+Q%$~4VGG$VM=VNDBFm0uqNXi6=M*k zZ!pUIrc9~`U16*I2(_-j&PLnP58%^_c5<`I<(*^?I++gU^Q-Ae#2AHMx0*c(r!&og z_nW3ABpr?n45IK9U|TO35-2-~vK)cF%uy1-`@ZZ88>NK*QvBg&O8C_{#^}_)#oVq$ ze0hZJ;;bsry{iJwm)Iy64k+o>A-*bc_Z#T!SRnx(+*WcwKs4PA5~A2^iEwwEqA-ef z5|uuznI|4q&TPgIBMM|?w?H*3IH^t*Ww*#5^WbllNI(JDyCh}kYB2!tDMRl>2cZnT z4$arLwO|+HB*mfs1SHDRfJDK5DR*p3pI`-GEMLQ#pi(=f6k1S_bJq~>oPwN18Qwb_ z6{jL{Cjoqkp=gq^AWh2i`>`8CZamEfb<)IUiG;HnfcydHMt}r$CS@1shcSx}O@ieP zdSqF(D103>x)2og?v!AD0WeB@*(w)-R>3Zj1+=Y~0^JLNZh_nq6m7p#B&Zglf3^^$ zPQ()y2=a@s=>~)y$3MaZ3C~4du&VZlQK{xrvh0`Wt~9MfPovea7aEE~?hq(FjbP=2 zm^g8{Bn@rnFh)9ztBv?3ENRz(5wRH4AQtgxj2tfHW*S+Z(!SIg>V2XNDJyajocK0|~bbl4-0*%iSoNBt)1-isDJi&BF2Do|o~g!4tr<9nYtD z1fFAfPT@HR9i=axfp{*%lZ7V_&p13c;-S2sjb|aA#dsdV^C+Gbc>aLruXtX?^A?`< zcmjAn#IqaEemq~|iF6#UW@7TBj*g!auR^FxS?;J9Wgbx}9a>TL3D~qiKQ2YO$Uqfw zP7-~2J(?L(91AGj@D}Pzq6{CzxvhfzVYRZQ<3z7hU?Z5Evw5pUE>&}%{i{LX^w>{L z`Bec(lwYz4?0l?~@@t0dN7de6Ik}V|JCnBu{N6&p2-k+i@E$XO!xUuDS6&(FE z4O`+VKmv8rux;9#i=wVp*mR9x^EV_QHeHB~G_-sdk_aC>32YuDHg_V49G1J&9B8VC za;!bf-Pk!;!SQ|$*n0sK)p(H^<;Yx!j1nvs#X(fqQul=OH*G>MSRE65HG;T#6-pX! zGEwKiBg5VY3Zsbxe3Te{3zLUrVJGhG=!emzAWnFDNp6g8H5gHCl?TCP1^OHc+8ZxK z1Al-9rr^dp&wCK?b+&cRja)Xet%Kvo30-RPj*7A&7SELq!^_PIV$vjYsO*QWxEV&- z8VrfXWWOUcIfZMHx1x_Q*>y-(Xw2dInDK(*Z_9pY3IXLvQiK;+bC9*+vJS>hP#^l+}0JnpnrvjWL0}d{3ltXtiYUpNN`Ds7efKyb`DdGZ7!q9_MEd9T6%&9HxjQaHT?5x&E-h11L*oSB7gB6R0SiF}*v0!0+%DNeesomiL~m9p%<7?4>@N)j=$8RnRm=W#+@GyJ;6|9Zu=lYY|rhV(+!9>akjE8 zpJLzOZm3+!KrveNs@G0{K?^Vrib=ze(`Qd4ijU(Y3Mq7(+30`_A!SU4I{dvT_)+e; z9tr)lQ2&|@{pAFc*9O8GIh7f4UVNNsk3gbucxSoL?R+o?KMBXOEUpUhQO zIgOa2dj4z2QUBSp{zH)+^=Da+<2VYd!G%>$Er7JXuR#BgTmQFko|M%efn65TEc2i7 zti0dixd?kWW-?d5LgP9v+siCQ;m!iXSs$uL{b@`RpCEmqaTWHHcvqo3?gSGvP@Yt8 zAj8|#y^`<85Fg+n{(#JouMOea`-KlNto_FaRPEPdd~MtC*|1M(xL?VoqxvvVu_r8m zWP;>-tr_*-C+m+X<$7p(7V)(NwLxyN&dbmOd3lJnh-4zLxI71|Ze_KOWn)9EZ$@y0Tc1-6F2He{1Xso9N60;k zQ5-fQAzQtx;$PS+KgaJjc&328o>oupsBK0f+@o_faK^f?QMOuSASUVr`ISW4;L*%{ z&8^=x0ad(>d#YefzY4gijV!I^H>BqqpYc`nN%WwM*)Mds;T@T#<^2{L692b5lP*Oj zwnum_(DMfX@nz+F2f807-S-Y=1drqF7yXGTI0*Z-5#h5}U4X{FnUPUu)@UOq=2uLz zN!BpDwdG{1tu41O0mgoa_+}4Q3%El>x!+f*a44&Irdt=6;}0nqKTzzk$B8@z<7aLB3)%Qlt-zI5 z?ykEXkWlMc#{jS!1~<_i01^LrKh$j~bXu?%S4PjJ#?s3X+6uwvsQ5Z&z7-MPqe%G< zQ))70L(AG&SSy`Sh?7S8hv>T4Iipr~JE5G1W>!2u*YPdQhIFlfQU@Hrz&0St0hh~P2F#3Qa?St+DNNtyz9y3!4kt0|D4O#&JE!TLk|F?K-PxOfDp3bSetlmK0$ z#QO^f9UPfZs@n6giAjAlpIxVj^IKG4pw#mELD~+1A%8u9hF78dXzt*70M5m?zeK$t zADF|@@6aB7_^P!nb`uVuv=XX7n~h(EeMsVttqSKs5@-7(h=aPD=2a);_KD4y<(S~V zM4s8qvz~ci&!qpW?XB|P-ZsB|XRG`L%;SW$4Ebl$|M@|c|9(||9Eb(dH5`$o8>66= zc&A{y-5*gix#}|DV`Rxq{vE^Ie)kAG{EN0)=U-})m*iRqFkw2bLR!deO4gl(qpSi? z1D%ht0ZBYfbin`g4~440<}^vO4RIh%N`y4!7)zr_^BUf_p?n4)gpcmX7PxVeItzF6 zr{wt!9PrWMfLzu;X|^{K|4auAF$D?Cvv6bKrQY$zC(-9tz`8dc2G_oYSm>blG2fZb z!eORVRxf_Im_o_6l$Hzel?-@r6@jzfZKR-&*_H-@i>m?`FIYSEDsKBfoDZtkd?(F)ZMu)6GaPextzKcqA7~deAG}IVn&_efAZEs_(1$ln@sq znYb;ImV4Ozp7Y%~Qxjy`KbdLwG3_KIbL+xwWEAFn;W@|U8ZY#N&A`4Z=vOd-V_u_!AFH1*h=&;YoetYpU zRwIxq<#-o4QwB6xw!W?rg!UfZxQ(*x6H4Kj8Eidw%g}1iJ z^vR)bK+7u>_;z?Jm#Mew0xJ!X)fwvwyBzeojYWx#;T>i<6)VT+{x&}M{f**hi2#D_5>j__8Q z44jp>ZifB^xpe^?#ap)`&slhDtxTUB{0|ysfCAqRZ(Yh%VcxPKnK*huSjM&Gtt-v6 zlD7^ZS-ZUT50(GtcF752b;(1_OVLiAe~Fn-u7Fcxy7TIZbX|$}-yHtxNFY zth~iJ_6{)E1yZ%^iNoSbCBi{}SQ*q@S<4wHcPdJ~=!`oRoAWc&4Ig>pu5F}sSY0bZ zD9R>4-a0eqt@)pF-l(>m7oK6zHF*~sl|%2#D?hyFYuki2ZI2e(gw2Ty`$I*fLfG^g zF-0`*Bg^>}dc&rBxNyrG3N*ZOY>FMAHbE1jew4Rb8rGp)7cjD$yF_0EQq=U*hvtsU zuu6ypu$kCThKt6kFzFXfc(3l-SjJ1=c>geOF$bZz=loslt-^*lSieOL62g+U(q(wT z5#CimNZfc1G8;JNRfxVZc{#6%OVD(8Do{2-;F^vW5DN(+$GOs0`HF?eI+tm=&gHhs zS{W)@1r}P(i~Q0*aaH^X)8G4uhwt2l@lMM@-0xajuxx55cwr%KRe_D~iz7tg8HE-M zd|P4Q;}w?E>)bgfJ+_CtFN@P)5eoS+1@L~e2?Z(xUzHe-JW&R|i3DMkt>U@tb08d6 zi#*0uY@8XrX#uxE3c|>`QabUY;M9x;hGGCx2QS0ysk=(hTP3)R3G$iXr>#hEjx@9W z9$p*vIx53pZxmZEw)1t@U?*jIZH35Nctv428E#uv;-1J-H2md15q-AJk&4hc@1RL6 zHurwt0$eVLTQN5i!ZaAh?t8Ba1Sl695rKJJ3W_dY2iqGqL^BDZaKn$B^{zsgS0DoR zwjUMjT;~xSK9|O{QW(?3tw=)VBMz92dK<)?7O)NLdJ`;TqQPDt25T-&siSbF^)f5& zOJs4IS;lhmox^~>e;w>U*et5vc!!Au84Uxyz2OVIuszRG_QEg;GIe6WXRqUn=0DP) zZ3+wGTGaI6zamCOG_^zDAsB9Nrg#G((g3zkLU z+~xaKA}Yo$8&45c!1xW)BMOZ8`RBl8u^GKkMi;FnM}^-_lkafW$(U2m+jcL*4MlTS z(lS07Z+JYP=581K1?i3V-J-2@#caYQM~S#Y)S2_6CnevuZp28jXba4!8{ogsZgGVI z;x2@7H~y!%4aZkhO;il;YB8!4&?4``crzZjG&`%+<*jw%=m+u@(aIvqTL7Ta52Ti( zrUMXz8zfiTD&GLvAXs3YKMsgh;wwO*-yx$XfJx4AzaTW@$Jz%)d$95DLZ*qCl$ zm#gm$?ko_~WD%t!ZEsZ`Lil0}W)XHv9xm3+2T109l=K3=+y?vyl-yid3fUdQi?_;_ ziBW(YOcEYA{E~&e;vjMP0$YPWHp`SB45$<5B1nQZ!lg}!J7dS9M8@5KIPA42J46c- z^nJ4|cK>B!2gF>Y`$v)O9mJEVe*ssG9pEw9;llfni{o(JVuD9;NVAyF47?~$$DL8X zZn-AYHF%&_d$M!XRg$(>cbL~?E-Z5S#-oO3z9AEh46fWSzK$iq7Qt}REaF%arD?^O zgd~`8#ALqYvPYhkIB>gww8-+^3!5crBvw7-N)FN`Asxl{eR#?4F!i}8J1B272!A=@ zMOmr;>dOhsWPunv&+z4hSb#kJ%L%c_B}Li<)c6Q$jO`sKh+X7@8zn^cndyp}zKHmC znZAgQ39*P~*vadyezLvUbrpstXT4sy#oK2@%t9)cmkdF$Z1VPK*4*Wkxia4P3Rd5Xb^w@VQHR>gSxFmbRKz@|sQ z5*C~7rvM6qa4(VzVf&#=U`WPr9*)0834QdqdU3!^+h5+?f!!fr8z3qWDz!(~i%U2i^EX0d>;TL~W zFGkze^+k4regkA4eBA6GQ?Me~^*)k&8OoIN9^P%@#E#`=Je3urpsRm*}cIX&Dpzt5=c-UzH z?(ri!%};|6jk(6tJBX`_u`|MxgaQ)Ev#;^m!r8zxb(@f}^ouDCRdV>M91LWH@ZHiBVX+;yFA#MSJT&!S|v zj*GnH5`*l2>~2P`sn{%v6L-iY$AuMcls*cmrC7bg?VZQPwRnYVfZ})pD5e2E?1IMb zJ9gH+@0q$}*i@c@w5HOKE|JNiVHT$Hd!=o7zqnii+e9|$4=;f{Yyt@n{6k<^5!eCruD}!c-oOya_Fl2O^PES|Ycq$fD5HsV2ZRkz_MllKnLjS<({u zcqFp4C9*6WSzZp_X^Ed6iC@+#zAzHMyj6TwBz|R7eB1lk=WO7YtR!tuySx4RmUogX z#he~;5`H0Aas@Tu!PaF`5sv?(48=cA2cHSxeznD)z>nekO2@u{Fm-j0 zp41hZnrcm%bXxnohBs|4kmOk`bddE)q|geym&03r_LO~cs@;DJpUF` zU?-6LgDl?Xsy&5^=W);c=xqus+fmi;|i{s&jpfh z{qhmSRkzydgm0U_AHdapIM|NSa?lC;)R0Q_##=GCb3~fUdoz*`{Qv-l^(#93_?0{7 zN_pQbE`MwA9u5AAk(li9GPqiPfvA@|=O{L%>U|{rDrym5hf@iL^+gi`*U49KTZ93z ze18J&RYAQu1~jfmWNvZ=(h)%Nui=S^Dyc->fDL=eHzOL~3b=(1ru3J|eY+PsCB)7J zIVEvkT+i7f6{0X9^cboHzTN<#zu((G;YPvE}yz~(?>LdL1A`TdH;DRunO~$Ds@4E*pD=rlUCt72;w^5 z@J4z0E%sj#NmRp6!yYgWiM~i^plbNYo#ca@k8PDn=o?VhR`W8PL<~ye3FtJcarSu+ z^9@xiY%!GcN3m@!%BpDnX%8P}rgtGeXcZ3tXIu9c`v@{CLrt|P9{9PrFMg)+#a&U? zibf8$t33i&%W|Xl2s|1jy%Njm0HNVXK;;YGLGY64A6sL}x3K1O1?)!Rw}?fTnZkUh zX+BEC-hf(QE5$G1@DFl%G-G`B4|(;4FEREmd>OCl?*!lKFG3I;Jm;w^XfcX1DDT97 z06`j!8b$Uoiel?e5KEBcU&BF{+z)3)z`7M0*)_1EROI%yRhFalC5vKLL2!5%ibFR@ zT&~zfCoxkx@mEP_Z6l;RCd<26IUEx~q?o-NrC=h0RdH;@zT7Kz(2KO8s6qkNhE z%I&r%{Jy@H(7Q!VBQ}QNWMc1)g7_hJ*(jg?BjuA^ibmmwRZ!R2O>{tXXQMjfQW3J* z9-7e!vHCISF~0bbptv?Ic8L~K7iz>k6O~)Ay+u5U;RI|d1DT;F9wrlmeiI5c4Q5u~ z+Il3ygyc^bWAezsYTb0u4&fwT`-1>|@l zlIBi{?H(}@iNaM~iMO($2Kr8TDq$KJX#O;>_;br<-!BkhkaL04EqjG3;S-lJ?z^BZc$JwA%5vY zGu(*|q*YWWbp{==TT1D?h@Z%KTpELTiqOuOEVa>xDdN$l>Vtt&owFu>&P<>HH&P`J z1PE~*K8gV?4#)BgYx6<%8i%xPl?`k-NK$}^QWw_~53wBQryP>4ST@!!0^+yHEDB#6 z%$ie=jK1e6YNQC~^#V@45wd^Jn|Q%8hP#1W!fS`Q#_z3K56Lzx> z+~0cxKd2NLsS7JAM@wZtGy& zhhcU(?L!lZAn(&ZCB}xmUx)$l!hClwmKtK3-;MEfbKxrjF5^aic3|6o&|b8s@notN z`T$ko9y^c$R~O(nY{=%vbC-#3fE4vnxs%Kz&C&a`TpTT`^Z+esB%TJ|msMiEYO!4= zY`xm1ZwTfDt?1P9SW1vb{970H95O`}_8Y>W0lI5z*!M6Vjnh}U0deBNmLXUk4-4Cw z^MU+-`GwvTz@&ZbOm^mH@&0r>^Rxd@{HK%vxfmO{=M0O1FXJ^BMI%%B%9e42{ELbj zrJ}0D2t`NmlXn@Ir%KGZ9DMoal zVuB1VQ^A$OAqy<4SBJT~#dH0q;zY<>L{Ma(o-#q!Kfuir`kvR6M`idJwhxs76F`;W zQ<)&k7tZjvRvA{w49(7Zg+Qb5)8BUP{LVwoYVOuUdw~y%}!K-ajS)| zB@Xq#EFWLWzL#;~F9Jq@PeUwOA_nf+?t7B+P&vz6a%d$xBsXRkp+)wK8jKi95L7`B ztj0^W+2#)v;4O%NAgH49+D(qYMS8R#Sc$Yl-e+GtD*U*B0=QP8)mEV`{h~iIw3RVD ze3I*|vMv1xeGWZ;ED93mR zLGg`gnc2Vqjc?h+Vz>lug>|&q@N5I7 zAYY0MBy6rE`C>3@HP*rq77`c8ND?!~q^*26h3`VIfHoEHVQnnv&YiQ$R#^!h0`1|a zB=jU=M!b)7sMrw82stJ8ho{6SdcRl)0O&kb;%cAS%#@WY#a|e|WFz@8YM@3+zp&#~ z&?>x_q3O88AXtn&2XMv*dj`S08-m06bH4PSR+;ONxw%qSrll4+ER3U+Ip3}mmokQE zRXx%QEgR#3_RBBR4T#543C?{9sb8Vf$YPW8&Lu0cAj;=ZI3i)VZo z)7vq3#j8K!)g}cYCUiqm31+juK@?VvpIq9H#Tm|nMxoHHb%@pDZzLj>J;70#%}w*+ zg!4A>YXLz^811K-Ix!8YN&K{zT1FUk&&iTQJX!&JX{KMd&Ou@gmYlEv)3F679i2e0 zOhE~@^vVP{ns043)!trXC*aA$lYu7%PlByiR~!Kih4e?OfUvFCL#yDx0^t0Va95Bu z^+)~cRUKdHE2^dQ5O~I-KlFrrHFhdsmEgHo)5l_toAq0)4~geqB&f9$*js#A%NX^r ziYix82BQ|rsLGW@kVa?=?%b1&oS04$7+6<-e5S1M1Z)`7Qa0tKVUNJt45SyiR+a#P zi}j*m5>D0xz?4kgM~3azWHGe9rlNF&I#^h4%WiFg0ba8?t5nbG1g6?H&Hp-*2Al^Ce`HQyV| z1}R&Mn5ex=Pcei397Pl4Z8_xaGTTzzf(mhe@pFIzZE&V6k4H^UiSbDOFr*NUPL>~# zLkGv_FGLY*&b%Bw7*-S)LQ%XaJSae2KP+}3 z5h^2x7+=<~S~EJDFNPiiNHhM5Q7wuN>g6H+(*z07Bwh4L|HsmPAKFWD4FNaR8d zU?(=#QnrScCtzBFveu!NoaEk#iRx*h>wds%u4L7f#HRcgvk-~eqvlKZ%KaPl;zmSa zY)X=ZtNchZ8NN^oQ8wWc)x4PT;Dg8L9cuK5Bz-vq zJDLKg!qEmGzVG6m8;LdzC87>prr_Z@I1cl9jQ2{m1{`1vZ{I|qXn>7z7&Dlr^5sRExs z8KNtK&;U%8(j5KqDP(Lb+lJH1$Hk$)0$a`pIQ9?5ob5Dn|9}+XS~{10Wm5bg^I=*b z=~Ed5#hWY1+p3-N*iN-b(ph}nC3*Hp$9-KrU z$JDF&Q^X&L8_ZM4{i^JSJG}TQBl($Xs;c#3D}rHFwJkaRA@jE($8!p3q>`nq z=u9*2g(~9nBczN}wFNB5M`?;-m7=;-6S2>-cd z1jLUqyJCoPeE0ou2FL#h-Bhb>vd-GfrqSa^AR6N=*rg6;9t_#pc+&7B;lZb*#-6|< zOr3xY4V{3x3|9rvVKDxeBcwkHiNaT_`AT0=1&8DIcu!#Leehd0jV(b{?`YJFCuI%w zn>4q+aDrQ(Hw7xfRHU4#8E;7X{pL?dUYQN_fp#UMnk}I6Nm6-A0`8BrEqxmhv2>la zjs*U+rYnLbcNViXv5JW;h_-^J@AN|``$?0IG>&!XyCKr#Ei04Rm-)dUe_sfH zq##c$zF?U^TlM3N_t{S|&4chaJ)km8Vube$nTk}V`_&LG21uFxp=%!Hs0gOTI z)u1-!T4LGrEM@Hp+Sp72_*B#?M2T6be#KgHAV96Hf@@ofd%1wH^%|;VgRO(<)Cz0C ztP^ZeN9aQs1aD+yZt_iVJm(k4MQ~`w$)gZ<8xl;@zb%B4n97vtJ1}rTPw&+75%!U` z$~EBr$fRr(SIf8kBv-yiH$|^j@*C`ei;<9&Z!8Cfnl9TI>z1~Mc&!eWCNXmWLALx+ zbw!g044GP91%~DER|znvO-DZw zu%-eU|J>L@owVexqWM^o>ZbN;md;=oToqc@y7X60(1XkIbA0mFZU-w}P z;+6y?wxK}N0}T4?GnjmtOdb|REfS(cfgHy)x6>ckkRnk{{yiXb_i_0Wm$yN_ouQN+)!SX}{vD+`cIG=7Z*TGQb^I6uD^WkqL6iXl! zkBc(K`|K8`xm)_zlK;hY_*FIV_HYf}PC`s`CFPppu{bv9#^)Hx5Taioq?>%?9dbPl|&5uL958=hY_kf z)VnK!U2sQIC!Fe_KBxE?yTR7VUT_f;_kmS~iXh}jKwLvmOxdO`C!TGmE(c^}o4Rb3 zk!|YoHX=#u)t~C(>0Gn7Ma!o)}Bk5Ht>7{UR z90p%sbf=%7#BkYO-N;i%^#st@wPX|dlI?dgi9nBg55X`8DcX$12$D_OVI>yIro($G zrUl%F^X_6LjBmjmb;D`ezkU`dGmKWYXhb+@Wkm zNAFhdrE8Q;Xv<#ZUR$ii&v@ec1^icag!}=NUv4O!b)XfBP6+c2)i;sO=Dyr z7VQH!Y=8>efS$rjJuww%kRwx{HdzLZWyIepp(Wl-2iw?kws|h+N1N)65i3PH2S47N z6JH=xS+iuS_qFtQwb~y#X*qiqHozL|@jz$z&rSl^qYX}MfX}rq!g94gke_yGq4%-D zT$?sh%lUy@$2P@k*p_-Ym<`8sB}OGF`@owk&LyDarwI@H38WLhF#`S9^kFmEUomdK z0>9MO$$Pr}RRq;4oo>H+d)SYCnvrmi{H6(_rS|AY>SrfjuIuT`+AjQMI$ zrD(G@5rm_;z!Hb;=!L%FFkEbkbA>hq-zhXamZae8q!17+koAnuf>SMfQu_P&E)THO zS{lsu>QQX^meUH&=G;YOb3DCx5HXDDQSYH(C;f<`wPC#)(4>k_UWmtWsotQd@lQy? z8SpHir>N3jIvV9~1o^>EZ_r79zny|}Hr+Ewo8@P9nhRo3n*rF^g56Izujdb*2XGp} z@w)s;^jOjBVv@|IS^4cSQI0)4Y>%0mUJC}Ah@#LW`E=6x%?xTp(G$yhG|oG0OH_7` zc6@K9-}N>^vU%P5yQ;PDHG6l=R@qwbHZpC_Nwij1wpLg3+b`VC*+o0P-=U8@y-j+! zWBlP-Y{T6uXp;9$foUWgA3~4YYg_hP0yg5Sw$ZUZMkl>itNp$;zT434?zxM5Tp=zm z(`J1@e3}d5*z%fhI1~hYiXJTw(s<&MYFH29TLHNZ{DuQ=4&g>}Ww+$Yj^xs0E(-h` zkTLq>DLl%??e_fGfq1q6FE>CFUiK7FaOj@^`2+P5`JHsyL*AY9**$l0gW%<^SzCS{ zbIzpd0X>ZTeSq7N@n?`6gy|jHWd)r0Xb(R{!M{;`hO3~u)d7U!0c*(`=tUm?rh*d zX(?$meT~E{N{*Z|lBY7O&)(%#_RiAV(RI2oX0Y`*NPF7E3Pb0|_l!dN`d855p11=^ zp#Lysq_3$SIs!d3fF2rP54|rgNz7zgeAI#YZh>F+I~8|6mTNe`H5DLi$_s$KpI~#X z^Wb@+K_9dNY#@wz}zH1XoI(JW9SdGGg+`pkd8az%FVJ*dR8SVeP4a zg{U~64H&)_!NokR4OsM(JY|u%Q|j9B@6kCEf86h$b)*qlMwhS2B)?lcvr&(MPs3~m z{T6#A;dGrLYgGm~qc<(hkjbvCxG$sB;z_42h8brvW(dIbmrN46A)_>`gZ&N>di$P}EzM+x#OBRF8QM}a$|B{lGuNbXwoF!p=^MQoHldoYIya8Lm_=GRPH+0&EfwAl@nJ94; z99Me1C(~7XqLWlqT{h5JL#MAHflY&YoX0K#|A=J3vI7%Dy;OY@0KFAuFyCCLdRP%w6^HZDtxVY zm8MT#Z4M%^xZKh$g{RkX+k(ESc|(lH>M}gt(zKji-Wy%M5&wt0HxG}h$Qros?Ik23 z&|x(yXi(5Z5d((lbzyAxf*q4xAuAGU)2uxy}oF*$fRF2ULfDjS5^@3nor*jMhtv4j9VMP z1U?WhTm$RthH|FJyF1TwPc18}-887k`-W#ZhT7uS-q^#IQhj3*ZWTCggJ~E3y0Mio zUN>uRlhQuSJ5Z}D(JjwYSPgBp@Gfeb!pN3Io%wq*$P)1!-fG@xcN;XVjubK#3}z}g zS7C~M z`-@Irqp0<0kDqxJOOXx)pyX6}1-eCfaWw+LtT(@mNK?ku(T(d_lsBBLpfPq7YVx^2;+isi@M z2XJuM^2-TWa=%C)L_6`T9BwzWRyxvswY)5;%l~3bT4A)k8Sw7$+#D6;BLtpgV=X3F zvoC1WSaM?MU-X=4xR*-Wu)7@v#!_3NWhNuE$~+b5!|n_C$~fmBTbI3Poq*$Gd0Bj( zYTsj1W=;otkXOE-TVvdEcG3M+YKo}aRIRGN-_T<7`opjYeNj1c@4kgnTS74qxzNhC zk!&Iyjv(E{qtdZMaL`J3AL$xTk>)#Vl0d@_-cD76E3c-Fk}nDHrRDKl(cH*RoQ$Y? zvjCukz&}}Oji?%T<0cjg_Gn->UAi|tNg?hTmJrrPk6GicArYIdhfqN+YvK|38vYg; zASX2OkWx9&xv&TG|KA=aOJu+Y>eX(ryo}ePtCF26mCv@RH+Dr=$?X#YM*p2`?8v3G ze-xFNnAs8T5mS3&;M51rbaoxg zl?T;8{&GFpmBP#nrLhSrZB#;p8L|VNRa(8i}BWg~!;o3gj?gL6NiZ&S^21@qq29^HGy%i%X z2WM(5u-Uj{?(gwkG+H6|%-}cOJ)Y#@MVqiL#)@uOv~wm`D>D)e_w7Bq7vgT$P>9H_s5OWwk}`E zEBgZuZno62za3zD>+G9S<1eX`!hQN{;bk}7MW~r`%AIjXM8%LBg;++0&lx0mf8CHV zh2f%{JFNU6BZOm##$*oJ{BQ`XZxDn!pjq9fjxzqS@NDkRYTpNjDMOHmb8QRrGY z`4+7WnOxye8T~OdKI~o&+#EZTr5lrjwB$_HpmyCqPkqE(4-? zZ5$qMH=aUlfx&GRd!R~M*`nB!V#S7+Ip_<;Zc;(nlFeeEUBoX7tUn#KGJeBOwroyPeRA#qJAb(?f)Hvyc%tl3 zcBM4@%C%zB^5wHi*&AW5%sWu1F0#5_YtIiwZVnyq?bz^s1| z6Ye6G=aQq70$UxBbf`KHnzQXfV&@|}qS`UbiG+y{lx#4oh8GFouZP1+c_B>ZrQuX-X zG_9IT&07|rQnUTdw*4M+DwP|BazUQh%54WM95!DW2!~b`dH>^C#ul$gFY@grzA+X| zJYIe#zF25=RUTJrYjPsHD6$xr9>cR_WDq$#BaaKZp{2qq4sB$4vbb5t(_wf8!9!evp8{wM>8ra(3h3~+U^Ax=?fSy@3n8p!@ek)`LU*H~kF zA}_0sh*gqIZn^}#eA{q_gu_@2TPPl3S}4Yo3ueS%I0@iKn07D6Fq{PHJj?c2=mBLv zhykKaUpE3H^z&69vVe}Q5rhhwrl{!9R~%vYR6eWJPD~zD3Vvc$3Vx(Y@YA}&#^3uP zzZgD7ke@;uF16l*l4TH((2jBgXaXG5hhl|wJgbDc@W^t;&+C zm{l2{wED1`!OUIiB}lIFKa2nK_`jO}FYw=!B|Z zyfRxzyDgTQe&bDaAy(I*Uo;D;l~c=5n=s&i!4Jfb??x#{L5H<2N?ahvWQN#;pH(C`8olnv^9L3f#yBoLsx#$kMb2K?lhPxw7QqRZIUkJ^ z0a4+kO&lePdkB%@i)9z`!g?XF$#x;@jzL)#UdX1|zkK?qDu%tGU8 zVy0hYLTt&y=$K|G6eBrciWUPVm~YQiQh>}j$#hqo_FiwXa&8p^o*~ z%Z>-pazQ@!&2H?M@HG9dnC5t}=qy2g%;T&;^h z-p(7ZkHGIxgOOjzt*V8TdH_@(ko@!rmS1!P3_xwQJnRe4!f*`I^9#vneQjj;5_~3YG#mECCA_#d!zK6?JIJMFOKUA-um$O+ zfx<^la5Q4QWI3x8`K)0>xvhd$1bFFKrCxDg{iITB28;ny3873cQm@>TUQ)WzgFSe` zweKTyty{i9!PYTB_b8Rpeg9vjd)#O73kP^^O7etd{q|v6ek9D61Ks_$amcX@&c&Bdh@Ig zWh$>lak77p;$R#&?tb|194@#}I9_~CKqDMPLSd__foQGP@hewhb@mG;z3pXg*>XR3LDUtefV(fOqlPPI z&1__2(yG%BFAoH#=9ARUbgu@&&~)z4%p?}r+Y}S=Qxj4a^Ib9e zQCW)=W|{RI{K+#4bEtpL<764sUCz=90iCH7&qnu&{BGDRrG~qVk|g2;@gvIzU4WBY zia>Hb%N3thD=Lux3tkZ4INA%MLFsWXh&xIJOb}vuL5xBh2S-PGe#zvE7sMGoV{Q;R z-NYe}*g20p5TWP;M=-g6rSVY8LxKat{jj`P9VW{GkGYh7v^tZ{oJ}gTEnm%=wC2vV zy=zko%4>H(N(#3tk{3pg+{KWghFCIo4GghG5;+g#Kf_EUBorPLT{RD^%X!Z{qfL=9 zH`yO^+bif&)`rNr8Kz&3`xqlKeUSyCl+N&-$-<@DbQY8}z4^u)Z-@YLC7o~fARQBl zki&ksd6u;;)F2Mn6zZGflwJ^ES3gGm?1#w9Tg`4XW}P@Fsm3j0U1-0`)OewK$>#!f zKAtJdm;JUFvPPZ$^#XwWu`^#w#!P&{_ucI68%oZ@T#jodt66FjpXK)+nrmVqnqV}d z)S8f1Cu#?Oo#k~5N0M_S@`l3j;v946RuJK>4NVaVVwzB0#9hoR4?365Q;z1!m{Nyu zQJ+vVJ|tx*rTC4-8Rq>nrE3qGckxE1NQN{1g^uuNAE1*&+TL&Wm_-sD{?^@)E^5~N zwv=eZ%<(z7_AuP#a@CdXu8^1aHO2)dHmHnWq06^~_BT8y5PDzpEQ8Opzc?Z%*e>AB z9ZYJ^^81Kl%1$o|m*R5qC(p8#L~y|Er5HkCe4^EioMR00797kBT|!&uBc{++fA|8q zs(saJ)ygHDs-Bo}VWjs#bg2iCud;mE-v&Kuow3~v&|ay>uYX)*l(LPnwYiE$Cu<)6 z6bR_wzU=Q|>P~zqybr`218OPS#4&(h%*wqvKKrJ+%kU_FS$gnvh%ys537Ow|N}c>4 zg*(J0Bjw=$8E8~5O>SrptiG3~S$|3XGrLN4{ug4c#WVo1dl*KRO`co!32q`6rnm4j z-{1Pf@vWTdJjke7FMRpo6lou;)bJ=k@MW^bj6vYT_kgq=FV1|gtO5}6;(V?@d?BM9 zi}n5N(~7*r_+Q+~>^4J6QeP>du&S~BG@oZytvu?cd1fHLgsQ&H^DIGnzry#@q6D=3Sm=)Ca^P1tTty{kDuZ-}5nq(Nk(i`J7Raw2C}$aC2rTn`WHquiot( z73o}ojdB&1EZ(3u({oofTU?d37%+VwYHT+3QrjVPCwQ@0nDLO%SG$$+f?IVG76v_I zX)P?Qp@M#q_yv&S*ME_u{9}uHe{@wvGb4kEC6kbuWNx~zB_pd~-SuA>*_|jy%<-f< z1|!?W#C$A9rbMJm#tKpXXm%qn!hunPRM(Z|4%R3^VP{f}Z;KCWTpOJt@Wju{$ zwcUxTNidMXJ&l^^9WuJ;xcek4!&H`+k-^oNQ?s(I$x@8Nk`hd_gx2Z@i;RUml`6*a zLBv7NTbg%s8@9r`V#7!{pV%=lahNmkC26?DAM`pPg83iB;|SzoOc%Qf;`P zIwO8Va17<%mK9HIQE_v756TIdSbLie{r2{DYep*Pu5(|xxdoa{+nc8_%M5e`CXOUW z5rWe!BO9tKk9|6fdM0z!nyP?Imm#lBreKm_rvxk%=hB0g&%DHc% z+DjCR$SbCipVh#S^P|y3cU41M`y*s2G(jqPXF@}7YFNA8gpt)kW!QAWma)`n^_yksR z(JEv|cv1D-eah_djnHe27h~Ayt6ZF=1@VM)LN_hQrS>^&@FVLUG&^vFQEl*x;nx>y z#QY&`H)p}J#3TV*$oUAYergOJpBxp9Ouea-qktt<+*8AKbN8_x~%#Mn*GD!zY>!AwY%B z^o1`696t#7&~E11yWkSfqKuns>-5g>0 zJ?G5ujX9iG$T0I@Rv`U&I%0xa3Awh3tq4;1I)-C6nOkHLeAKpc78#zo6NEEkFk2#g zousmNKbaS6QuL+48!&EJ{YRODlf3hCLYG^d3bX&^tqCsZyIGc!gOSY^9!XLJye=F)TTa%+MKj|- z;R`yxGw?DK2+w%6%GweE+}gqygiab{?}_FVV%#L?mLsiVMaOC&?%3U|pKPyUVg?v@ z6Coo6&T$5XU@r6(i(#m0r@TP%og`3BFLs$r3Cg(KH_6sl#VjyZq4qJqA(rabNxq-4 z!1!5x(kZ_6*Ty77^hpI~ppkyuUH zb(O~BA8iqTS-g<7&4mn$M+&jnC7czHtZI(Th)32nM>^w?_05rA|3Nhtz_tgAgkcQ)$s26jsd zrbY6iFlVEB$=7{1*SK?mhMf)f7pr4 z#@&WoRwA(;Hq9i!g<#pvglXC?>s1-n=P$1oD0Z34dB^p!E&P!FOBL{&?z>t|VX`0g zbACuWQ{>TpNIR43zsM8r?e{2L(3hgSu<7hoD-uGHEf||n)Y3zQU=-Yx53@mt89|%6HI1EzgaJ7y+aS40M>>A>?}ZbDwt@By8pLOYZWSYRy4C8EOE7YZ z_ZS>A;geTB(OVx}Ws{v43)uHQj8{DGI}!L7Y~*N6?vr-|xe_X5cj{_t!tgm*1ao=` zHIq0hdk%??jV8~sJOQJST=3^`mp{^E-=Hpk;^kR(grouElz?$#vT+4H`U+c+T^8`E zA&pG%w}lJkg|nuYWL_GS$u+7ccpwCut$&*Zubcrr%v)IdUiA^ z-zB+ir)SsvP6m?Y^z25dHi8+i+{OqITtzx_g$5!ebiM4zbo4@1BQ7&p92d1NZ>-}B; zW&gvLjl&gV03qg35C;F^P>RLMIr1X&H8VEoxr_SDoivOFvW!pZW9y&{_rBXPJavE0 zlVn{f(tOsf8nj)95 z&c@SbKowp&C0_MyXOUv#pzaIEzVJPqE-B0m`r{a)gSl*MNeQ-ZqK~UN{i2H0#LR6$ za+FOQ#um|vSSpJd>I=HF2S_&b;_G&>420A|w!Q*GXR4?1&z6`d^M& z!l3)8^-tL;u5)~W2p8A3y#Gnq$=hft#W2J+3fX^&l;(a@zzny0NnUoLvc=-vHs=Kx z{FN+;&_#yo%%@2nc3&HTunt9ogA2S(i_fcZ|A}lOo{mtZP*8;>p4KVxblf%(PseS> zgN$5sgkU<0bjJrN6C=Jj$gjvBXVZ=3fY?8>^UlHGla5z%k@=@H6m}QdS*=T@mu`|W>VK$R-R{j|KYYb+&A zjKV}oga7L}IjE-nE7O`Va}BkxIP54pnTRHF;DNc%!X_>tWo{2Pv0d@OgoZ_Ql2xs7 z2=91C?rGGGh;>>;?i5vV_sZN<1y1L1yCedYhuKN8PhUh^7~^;MvgQm_R~x7YlK&Sk_8+n2i_Ff* z^Ug~TorBXAIkuk3PNEqQzm=C}h>1SNd|2$uT814Aw%oA2@3Ke=F}5_m=r@`g*L!md z1-hgO4Pv5Yfz7#e;#eg%|HbKuHOY}*IB9XI0{Z7qTEx^T!&N$^PRXVl>A^oOkyn@7 zfMIBd%)b!H@R=^zT4+-Q_C%=J$T}eTYDZ*HA$5$- z6!{O0icKe}Vxg0$Q5kC9M&ZpGl_jk-DszsdQR&K%O{kZRz?QNc7S+kVGy4ZG60rwe zVhcui&}0!wbNaKdfE;~wvM>7^JaR40M5^^4w$X2p zwpp(O8)BC?wzr#XR*jYh?=r9Et#ATA02T3;`)K*8zUnWW?555URNt*Ka1hLJ2J|Me zMO6!MDdV)}G8C(J_cCHCqcaJ?ygI8_?xKA{jpD=!%DS-whj*$*#|=WQOm(4q}?`dO!E%H}HXEKJ_AFh?7n zL&QKLhVq77hx^RzXJuP$_!#PWit0qR93=(f8A)mv=2o5@9-AH>H8c>;_kn@vs(~!Q zFnI4y6BbA!OC)6>rZ9OIZ>1+|Qi!p7T(HU(+Y$4XWKz}Ur;|vuwO~=6EZ*d#TzXA@ zvV2u!=r>NHHYuYaLZ(F1C@RFFIt0uoQHYB@L z0Rd7=?<#GhImFH@eb$@wq!h>%l}u>JwA046I6)-rDfbR`hs=9b+mt`3E1@L0bdUpX zC$c06ecR{{mycn!idGMtQmV7|BJ3#xt{_`B+srFTE8ss85Tw_d;Y@pMSuH#cO#~LHZLm^bUNxUH zU%4-$%Z31Jcx_nABx0tKgwN3`DA*U~OqDuM<~g~7IurMM6yB{;tM5)Ib%~T3l8una zfZ0;2=)TQ$B%##Em}uY4oRS^=8ison3p#@byyvxVMsg`C6T8YpP9z6%E&HQBs$m;V z;~!`S^0T;XIx}FDGf(Aa3hr$Q_w!zsM+*R z48oW~CPSoyO(GrCiFELWNC(XBMOzDv+C1ZpJmWo^*wv7r?|l?`*cN@m6+^p7m4k166%MpLE2EyBzg%CMDs#BYnok8crQ6_3BBMf{`j`035@5Nag%3%;29 zI1?aXpJF*odk@XFFcj9k=BRiRIDP#DR5S~8`BJ`D4$u@LKaTR?;f z3`o0Y(wwTILYGm_QYohlij>Ob%6nl6;c_TAYF0iYeg(F*;tDy! z2H35{qbT3)4ttZL&XuCBm!g{G#25p(LXyG&9`;E;)S4^1S)!0V{#lZ@8voajj`7dS z9{(gcdi*Dh_IK|{C_|0*TPCS8Zjv(8Xs;v5uNm!+$wD>(sY>QfH*xu?V$GDO@~9KKa=aPNi_7oCqn6I&ZT;*=i>w3>isJ7D)~ffA02MB_SO>;T5IjX zTM9GtLl%fqoha!P*$2;7I4*|ZzBKngEiD|}Qxo0kD63)O<{~;a3#`_g-|^i-b*r85 z9r6JHPPYMQ+Y$ir*c!>bx&r#WR^)jAI1d1DPBD@=HftLZN(;Q@W8}yn1?@CXIwWT3 zuAUT%X(I#L9tYbgr>m3`QtN`;QzYEUCLB>KQf7PNC@d?)#;q!>yB5#?CHcRmve;gJ z!-?c=B}<3~{aCWZC9Y%15;>%fu?9t1V|)gv`YY>sIgYYOronsE5AKT!%Z7EPQpGm{ zl)n;fA7l0g(Z2UKYKKB2OZHwW60t zRQm4kp`JFAt>TYCFC8RRj9w0hp_h+%(BGtOO)uT;w2EHdB-t_P<$f#wf1{TO$$pVu zoYV%rbOCRFkUEYvMS8Jj(cvO1vBnTa*OAfKa-ERH zS6cx4Wol@r268KE_+Oz&XPzyp3mk}0ci%{FDzUYmIwcZ)#lo1j#@^bLnQyNz!sx8k zWT7R8MtsI>XuQ_!r+#lN2+tm9dLChJ@YaOnrt-qQJ znZ)8XF$2Q)uAzeFWywjjCypAWV2R`|pg8kfz!pZ6>GO`y2_*%*vxf$8-l;WmO;zsY zQlU{}qJ(C==Z@s3TEem-vDUyAZ4OwWhH1hIZwFd(7{q71ED7%nlKhN>2PxR==(pNP zuA|q{lT(g0_ldU!X_5uQ)3+qRpd`d%HXeZC8i7Gch!2zG*GPzYRHsm9so9iOu55p! zr1-$@A*8h*L5O!A82nB~CKw#71c0;tD7zruDLJ8@0q=sLp_6RU42qR*gq0O)2^3^Y z7H?75UNTxe789`=y2HCwuO;ljX9giMGxhYB? zhvf|8L38}0vQ${hKK(8t3&PhAH2<6{2>+84j|lYmz*Dws~$|NjaX&Hh=3mV^mMiW$*Cr@)PZ%$U0A- zEoHN8fNEg}0#NW`1x&~P3e0-J?au&nKi_O%LLfvMY*0RUvpUDKe3Rn6xufQQ;gurp zMci+PxSVmI7Id2*tz{#PeA0J`wrPrIAUXHoo7yl!h+S)*P08wRUw&1Y?iSxV@lDwK z#6g1FS~DLjE__HdYj-VCQ5|KpgxcqU!VKDrOIrYah&Tk$fpGzJwS2c$-Xef5=X(NU z*uYntFPhyYV1_ZL$13ZYCp56`dtZ^ zYfa?nxqkF*fcoX{WTxI|x$K>Xl8Xj~(t};{!Ua8(v6sOD(uKuga>M)JUq%)rS?ABL z;rOz@I?COuqtUwANBhK9qxonbhtAdgs;_ef<3qpq18!B_hQ!9n>iS?W@sfYbqmn*$ zvuf}2MU}a!86PMQAe7NaplDwGurOFi>uN?>8u zTmlEwC~`uw-zZ8)Fu-3;eXyg9hz(vUPHg*$s_lzt`y#vTX`Hj-G&F5rl-#hsMcbS2 zmA$aJ?O#D>iEX#;mbKgdeq!5CRBeAk(#P7K13a|7Rg2ST@iXxj1AeG(v3;146W)H~ zZSyYjspH&COAC z;*YV`ct}c(tu-PfGiS%swq9#IZKqXhjY%Xs=2|1i%KzWi8a+t%i))R0s11hqSdqMX z{a%{!-eQHNW2`ma<;&4)jfaRm=33*geE7w+#{bGn;P5$#G-4i7Gv?2&T(%#iujEQ^bcKWv*ffK>6 zzG=RPPF+lw-z5C%MD|WCe{Ha;XUVLY7x$MjZgF=`e>^if())>o1L_c0)nY8nWG0jC z!Iw$Sq2uwu#qspZ)oZ{NyoBCh>rwLu)@@+uwn_35>l({!zXiKGo>E{@9m!`dBE9(` z3@OGdl#1Izv)?YnDBKO2wq|t9FOT9kZU;XpSIdtO1rHj>`I} zOx^qQq887xAEmnnbw88e!Q*S4f`5SkySa3t5L(n+9>_+GBS+8a>-f=gd=tDW$=PaC ze?NEWpx-Me&()=abT&>2{z9&}Q-b2Y(%I^0eUy%ViWBFLaN^vRS6k3ifMX@NLwXwy z#~N|FxrOurBlkM={&f2F>UGu(UP4TA`onA|DZ;rv;uvTTT*ph!<8uvABKj-ceMs=5 zC3ePEH!P`h(}^}00uM4J{R}6d|_7yd)21&`kBfE!JT52Xt|d*Uq>)yy_RS-9iV(^&SadmVU4tn z{G5_vkA!Y?{=}dE!RSoAA+;TsNm?^rCL)Q}TI8ol5)|@CmmT3Qo*s+FN zsV?G+`lf8*OheaDYGu_C>|VQSKY!A}H>FyRKZM$HVFXF>hCZd*uXEDWvJ7Z3cEQj1 zLgVcKE^mxCaWpEflw=cO(F*g_BZvws{~WiSTVZy+*7CC=z9ef4s~{wd$yO-yv_-4M zJZ+JI_!0ngEY;SUHP=vp-zp#jsd;T+P-wlf;Wa;>CTggfjK;lv51_g(@DzNFlSnp0 z#7pJ4^|A9)ag#g@roI=gu*2|@F2grv+*Y6W1JBKG073!V0DerajG_whPRbFlIxf31 z#8cF`NAp&;c~lQ2d)DEYw}EqH;n9egI~n_)yI$e+-k?y0=l+ca-Ug3yE0nz5vuv#@ za^}_|<3BR=aZxe#KN`ibWTd1dKX;=`Ider5ZZ@1H9ljHbEv}%Dn%wyRmCty6H5vhR z4b6GfuW#bmls5wYMlL#(m&){5%S;($lA*rtOnKLu_ePH>8HU5me?|nBn}xj1mkKG{ z4P@VU(Q={KgV=9WVm9=!XgAE}v*@a!A`oD@>JDSsr_P2Xg$s9!GY#6+Ca*S0jt*Mf zQ|b4FS}CWWRSt~O$9FrjdpuHXf>q?wz4ai)Z+wp~{WMRuGHLZ>N5pK=lRd7&lRaUT zC%br!Cwt~vPj;xvlMUu0>N;+8v8*}9ppW&jIW{yiVED4IYfH-8eJuTGPz!W6;?!q>7Cly85 z%TkM0p@ZWP02<#eGJb4KB^{S-lJXo%d3h*6nSTZ}D6_zrp2=z}M_FsJBW#Fe3fop+ zu>STLADS0~1H_9g7Lyj~#3x?CQ)27smoF`WmWhB?nQLxOz{U&9h&d5jfz-id}bDi>XM&;qZb?t1_{nlM#xcbe+%? zwmJW4?9TSJay-+S7Qg}9`XX`^nawY6a;S;M<6jO(6_MPNsY$9e>yRG;;ao!7}522+KcC|KEaz-oij3 z@h;PtK6wmBhd;VWq3mN`%Fp9t&=`BX?_DGN8H+N_E*NJZE{*etCu9{xib3S3L7yMw zsV>ZM0_Fd(3wMXs`@=;?ae;Bn)3&YYhWg67%-4GkICKD z(;r2L#PP3mb0Zs$^3lkHrQZMx`B~y<&Bp?YkI4YYWNlI2ijM`nX8Et+V_r(J_}B+M zRqF#5AIlO3Cc9?no>758gNe-S0mXEFj+t3gtc_=`Q}7u>mgBI--GH$L_c5Q0)&VTYCk|abEm8)q6i7X7-H+yd{}K zJ$Kfki~Z0SPCG1YupuB0qXORRGv{891>*ty-*9Er%MP+38y@ER?i}IoEG>hhIFeC^ zuL*keOYm`?4K9C6zj{N`u;fIi?DB&mGA2coJRO7w`$$V2N7Oc z=oT#*sLl-WQG}lAQ>52w&4&(HLXW+ZYy1$&k5(RXlranBo?Hk$OErCWG!C;5r*aBX zjh#hTkzb9S)eOVD1GtZ5Hi#WGHg-kpTP&-dpgJ{y9c#^XyMkqxc@}SbK&!P4Qd6fm zK&JrEmj%{3Bln*K%nk~&gi>Q57Fr-~XKTU&am_D-_yRJdX{JznbImVgXknf$ z@NSoIWI>kM4pOB}YMbZNOihb>`KVli<HF2)waEi7Z}IG-_+*HDI9y1#aKI=NBS z9OQytrfu^<3ZO6)HKBcK{jDH5|5rf*WH~LM87I(4OV0Z5`RxXrB3YEAr}{yOUGU`_ z5PPu-q!~)86)SSF))DT)whwHJdnJ)&gi+WENv>SDi!&d~M(fZ&_pydAOs|-q!OrXu zB9xF5M$UN+iHP~4f5nX%TChVS&RE7UQ@#`IEfJy9ClZUdO>@zweUtx1} z5%I&)8*ji14lU_mZ$F5G6){2LsEXuzhg_b!U-22|)cXwaMg}&xV4-GshF&u?gIc9q zJFtRKprh%M+GIH)rH@gyI;>jL_WKOIaS$gaYKFx!lNYEBwe|7e^5&7ymu{;N;^K`m zJcKSMQvZ(NIXLR2OxO)R*1UD)?GP-Hw1wApZe-`Hy8QU~w2MT_3BA`F-}Of(GJ$?n z6z+{Z*;heV-**~Mw;?TLIYOM_t3usxOYkN4Z1M1+=UaK zRI?2rDQ2IbX2D|)mMWBn@XgsoAz%@{Int6I@b(XO#`2DSO7=zQa`6S^Z5wI|c+U$t zea6YYsPgE>fInc$NR@#f?FOYK7<3D+DV-TqXoxd1?*uzD!5CY7;g0;EF1P&rh8AG; zde>lal|2bye*;%2mlGdxjC4sn8UJ{C_lynQiTV2mOVq1HO%meDh{`A zBBH?tWJEI{j6Q1st0r4OU}Gh~c-w|ZUR2zn~!2{Wr_`6qS{hXjrWF*=DspQKpY5W%Vi{cjxP9HN$jaV>X4`pV%MFu}F@ z3f|Z~ibq6g1iftaFye^1@I^>zxazwc#jn!fSA8396`YdLf+)8cqF>LlgzNkgK%7;S z<|zwJ(Em&D+(5buVPUpb!y4yVGS2N`E~ET@MtMWmnFiT|+|o%{ zE1dtGQGN!78~(^*meX@`%qnc8Wyq%;4+;~8{BPiH`zWFncSD%84xb%F#gCV{A9=|i zLeJ+CgMGDfaooKPS3ihe=J5=B(d7QBTqWD7UhZA;GTimNSP8!Ol>$~WFmUYiZCkAj zuUZ*utPIad1~Hx8ZjOnke8o!nPb=j!R?3IeuiO0LoJ0;0Cyv^U{PH-_W7+*G z+NzgQ?37Ad^_l%ksZx}sneoHRX*An>hK%S?jPWirZ87FF7zS77UPsMZup7t_AKh%* zkK`2|-VKkG$>vVVYQ*~5-Q^|A3rB4VjEB=$IT;JZZ~2c@#fLKk5`a2ZXL0!t6H_91g=*`C7h1@ zj@_ueVi5 z(^d)puuFh@ws4v3m1428hYusxoh)(~Yc{k`tl#iSTKNj`TS6u<%(hG5n|rE+ky;W? zs{OeOQ3;ZyI0p*5Pi0LblebZLNR9o9mUIkRIg3SBr4~748^+ZEJJP7AISw%$aSX7r&QscR+doyyGzF4|<<}>jn%njNiZ*u(6(W6! zHdnE}p;p55=^()#eOPD64(Oz%gV>y0jO{AfbYAMFkky@42Fi|C=YoJ*~N| z@2J04@LjPf_WuGZ6OpUz$T$z8Pf>xn-?CDmq$h!NgB(wCGMk$V=F@GF&?coa-$gH( zVke0@N}aSAG(J7pAz<`ZU84-I-jaR{E5j>Ms*8ihNX$kJ?o!R?MDDUnS@3z^#+c!7 z+?c_`>3O)zA*>D9$g0O;i}5`?M9()8LrZ!FGX^LawUWvKmP16C2Xba0_j zlV`9?_->xutMsG!=t8CIz25xOT-CX6sLplFq(xtf*(MUHEYIQiTsn`dc{|@zZIYJwYmET~A@=#ZpD2_8$Vu#^bCLZquP_WZh8rSr_YFr>ZFF7!1o*dTV^r2swpE6l5 zPHuRcuJebx`m;X}6QS0lT1gdgnSmWGW!EA`D#P})9@V?qEK3~Kn>@FyqHsp_=e#uY zk@m+L)oJQuKyMJh0+F8f$mX`Af}X-B7RQFRZI=2IrC^q74edTf#xw>tE3=sVFqqGb zvzBzwaGJ_=(5y$JW$p%;RliMl^ac4gsyr7cl9DY7tb9<*9Yb>#UXW$aT?=x|C&&pr zO1@m9O0f%&GZX(ia{a|kmMEX6s@kS>Yj!1;&T^>wkf^gfY!r6;ztGs6xEJowQe$InPSD?KdXL|eETV1p&fwX~ zp`sc%rVkk9>=4_J!A`R2$@Yy%=m?2&C+=5%7V6gIZ=LdKZ`5Pqpj4dt<(x>6B-tiM-g^{eh{OWAJ~HkwVRe#D=s7RYLc|Z4sv2^n(!{v&>|_Y z;j-@3yaStXk{1Ze#@v;1gLQPHf6HE&mglw;;hKK^qoT+x2M2Aode*fy>XvPuf4xyx zxqElt1G!ZcG1PNc&3Y+o14BXc6ue@*R`E$w#rL~6P%XdrZ}2q7AFBAiX@jWjNVfs* zF5i39p}Ea4_V+zdy*tUXZef4D^2-ZS4q<2G-5=Upv8Srya7C#7%25#D>(;N}{*|M2 zz>NLMjYc(XZrf>G$YJgKoDo?;(OPvw>V_z_^w_d=v$hT6G5kmLfY*H_!NT{~3xL@2 zw3nMl@e+6`d$Jdb%4kaib1L4MMlxM$rKgKR?tPc=F z2Kw=vgVP-5YR|gU1w+al{vW3&mw1dk@;ka?X=~&ovwY z{SzNH`>Z+EDlBlVZ6Wfb$xSlmZZ}1T`M`M*fuq5stRnAT>r55vJkN@ki2;%GfS*$% zpLm`NjyW>TIOif?^fkZtz0kgfXGsuAlGz;xB^$lPb-#u5dl~%Cd{W z=>~2@Zft`E7nVL70B@MEh(AFQYQt;29-J);Dbqzkjl}{!B;k4PoG}*UulT)NLrs4D zN7?8LrQ}D_dgiTY-{_KgciOO8*ENEK+F%CK`E;)N@I2SqGtKA>m#aqU`+DeWl}*n1 zKn(0z;-S6UENclgFk#!D-OKgn`AN+%iE&q*Ia|f-GTZZRG45r(%9gx!pW7z) z`#lBq=zhfU+Bq+wDbd!;Bapqjh$}g~X4!dAr7wGX@G^hooRc8HDnzqB=07aTu4)|W z51-dOG<@0B$`+=fe6uhKH97*Ur5NQ*yj*zhH@3;ZcmxDMQUV%;n0KI!A`=&6(niPx zGpcZ5ow9Mo61#8J%7A<8iZt#zuEGQ%^o?)OqV=AeDl8t8c>Jz)fB*l1$H?uY|93nl z3rhMQ@tCk={OvsEeCbr#RFCtRHBkKjw>;*3!LSXJ#bcCzYUJL(@ufA*W%ysfU7DI+ z!~t)1lh0f4x#<%bQ;2TH+t9j01S34HRnA z@{F|Ma&HNT%D+P6R_D)t8^KZ-fACcJJiNg*92Q0B806m2bcRSwFVWgqV+0hRksmR$>kXMfwDR31`lVFy&?`F+^VAaX$$J zZi0IV%49Q|w~}XLYl$XwFXly367~<0ufnXCL(xi}+}-e(HISdY-GE z1J(0<^&G680!OshQ1u+9o(1YTTs?j2IZ{0X>Up7hj#1Bx)$&4C^<1o;73z7DdM;DX zo7HoLdahK@Th;S6^<1T%cdF-I>iK*1T&s^|Uc`6u;Uqn;0{=U>(HVfB1eJ^!Yj zPpIdU>baI@AkzJ!vzUv7XpH(Qq2UrrV~%PVETO9;)K5Y$ODIc1KT7B%3H4(tZ0IbZfP_*d zbe)7W3Ed(gtfr#V9}(#HO6UX0`-z11N@$yex=XsZBy^vIM5{XeaS3gZ&?X73mC*YV zdRRiAN$7qF9gxtS5^96c)38E9T_vC3KC1#!Bc?2~CzzKtduy zH4KwbSV99O^st1)ciZ%5CDcHFH7h_35oNFhSd`KSVFf+Xs?8p zN$5uj-6)~7WJ0qg)J;OuBy^^Pt|An@ub19U`#nVSdp+${hxVZUFyT5!%7+epivxWf zzvM4^Uk|;jHbT=zw40}0a=NB1NV!$lm+8$ZNE6l5#HmS!=W6YAxK;GN?s{hp)yE*` zcx^~`PQRzj(5E)%u)gOpLXxi3MzGy=bxNszZR_tGj`k)`)AF)3tt90}y{z?j$)9|s z=I`=o>LTlhd@m90NG_7MFJIAL-3yj&{pk+8T%F8>jY?<9MP!aJ)vm z^w(K>kIRmGHASDbov~Tx9{E^`c4yMPaD^vQQeI4PKAS@CE{TzZWU>4B0!_QXakZA0 zscDl^%Jl2vD6qdvA33hk^7%d`C8*E%E#G_TCu+9<-z~c1aa}X?UYho#p7OG;KbP20 zq2phlu7dI^bjM$H?ItPj5j|zSuCHxbUI#sO{Bacyz4Q+xUP4pVpQ3Sg&N?Ue)4FBb zG(S+&1}0yj4TZ^DaI7TDO1;A;x^|xqTmM{7IiTxbw=6$b@2A~Ex_k8Wr<{PWg78z0 zwhuV94Gw7PW@p-;o!XsFX8ylAkK5?f|K)7Pn$*)*KV4e^J73{&-|3`3la@KPhaD+| zpK^=`UC!ekcItmh%q0EWOPi-@^W6W@wN-k`m%4VpoG=AL-g(^ue08OHXOib+ct#F4sqE|0LZ%^>(+qwJQBh!VzbuCg{vL7H=lbv?DGp z>O4c!9&@FA?b4oerNR9-yPO}nv^QMr2kvsE{M)5}>*}?}t*>?`G*sGo8hs`G)pnPz zg?0Ezjh=>!wRZ%DPxO>;b-ghW9EF?H=vj^b(g(lO*;J_2({}6HyE^zhMt2DBO4n#3 z|Jyz3&>HlKcHg$_>(jKUnl?4-A*Z%YPkzLy-Qs9>hf~|+82Xr#9!nwScISCQD3sSn zGw2?}kyh){?sg2lGYn_b$I&bF_*wC9~^Pr9@Zoo-@wI+s(i^l7$!a`(14q0O2s z^mBZj;2gg9x}Nfpu5V3jB;_Zc>K>tGfsSL)WVemF`>;c+(`Rbhvkv!94(&@v`VS86 zpySkIq`z+kY)zY^X>&SkOJbnWA@}MXYm>Am^gDp;MMsBqN!nWuqW3sDJd~vEm*8?| z$GeiWdz=U`o1GmhleF#5OilaV*>S&HyVXV4-0$kR$E`gn!IxYe-*jvB65Q?T@Vs05 z#x+XQUT{CI?@Q9ZOd?t#K;dA3ewK#tboMfxWz@TR8U(#dZyRw!pZWI?cBI_w)c)m6 z+2PbTIZuw|1P7;T{5rYQR}QUT`iBl}SO=!FnJG^@z~StD4()di8VHWZ>7z7Y?iZ+Y zGdj>?J0LU4Y@xl z<%J~up`>{23a4Ek)?J@Ew7==pv&P}t3dSON1dHM zO{Ed(yHd5+ogF_;)oypCt#7Nn;7V&q)#_a5e4DEM=<4)ks`ik3)L96N$#{GRa=*w`+2H%cWTh>rbb2GSanoQquN$w56$@uRPkHQqvke+RLe(8a&$W)U+>&Z`~Ov`;e>}D*Qk75SLn!h}@zOSD`@Q{uWqrRnSE%`!c?RrhSzU`;N zP}BD4+N1h7mF_t0CcwDK(e{8-`==xAJE!)tV~bP(tQm?7lm7y#Cg0}JE_NT*wadQX zqa_y!G55Vz8*_rDU6-;zFK-?s7GI{-FhU2F)gi%Yp9v$^ziQE^B9FC%^LUNoPU!fQ zuJv~RUDsCVF6Pu*^;~I|#YbTAgO8u7jbn%a9$y?pp(~jf+?bcp%D6Kttx-3qHa&8tv`=@>e!H;$9hNXPrZzr{V7kVt!wAFfd zzCA0+j={vE_Z87E!!&K!iGOry6Hcgf!38t^;nFG`ot83bI6Bt5w40pC@3>$=j^|w3 zA5{1Or_9zHTxoSKy~b4#;|{7VCn$V(eB8mbki6ERy{!8QuW-n^+QvC}?B?#P^?<#d zlTxVXCgA*NT&8&4%u7SAmh9y3L5DK$j?Vys*}Y+ZddlB*{h@>ovC@W~A~TCXku*jdf=oL$WvYHv0vyzHysBsNJG!<3nFq>F`9jxsHWy;i4^*9> zR;-Q2Tyc8JeEo*RGW_}wyJOv-IGL}VTbfbc&Vokf)Ri<4^{m@}M zO;GKkk7hz+(nm-4;qe-Sd${{~#(ny8I&w}Dr>hO5nV(6Yd=@TX`>_n7tPa{sPNp_z zGQx6=^GQJD?-$}*j763BXCAD|qAfq=(3v@iXo-IkCx3SQ(A$UhJ$L+=Kv6;QjFLIU zW%GT-lcs8Y`z1zc{nXFVldmhD63j21IeSKNu%vX>#GqC%DLARDcv@yjdFG@UW#pWn zSyp^)NqMlitaxhX z7iWfMHD_;;T)vmion;j|zciG2R;E1doGM#+3AOgoCe4^pI%QI@v~2JtL(V_n{#Be+ zUUFmc#9-#E?99_=ot{}dZ%T3T)bh-kljfDo49(0e56zxkS{9^uNvBEUFSgrJP&R39 zKE+I)H065j>~ZDAW#wm2CjG3E>(8E2I<@%hd9!CsnpIpr_4>2NmQ6WZvc>}iCFOja z-)D*{aa_D{Ey_%+Y*g|5v9n61O)D;Im7~>%5yio=Q_6~qXN`@48;==Q8k#k=e8h~> z$&+TNLimz5V@6TwtP+s&Yrc*i8_QQz8Y(Xi2s-KRV@4*_lTZH#i!UpgHMMlEN^1rE z&ACw zhk~lsSge26QDBr!no|;N)$)srA<&Xp*9J;vmITXN!ab&xAwWm*xd_5+`SFsHAb<-T z@%CI?JT2eu);P!sahFWGz8JEbTso<2>hRJjA*(jur1GO9hm}#M)sjm}hnJPk3Ti)t z8-Kao;8|8O)&15eDV#M4-1d*WIV3kT=eP3D zF=Zul$lGVS)?+%8i=bEDXAQZwI5=^3S@E2#Y#E0ajtc~|>BovyITAlu;aSD=f>ze) zv3$)@Qd&Yj>qBB0Ql-jQQa*7i;8-PPO%*DT%-I?c#=mLPWAV^TGd4g*{_wFu890}e zj=dyc(MBLJE?6?7ywA)@Q$3Fj-?izPVK#He1eWuKw{hO+sSpun+7f&f=-m(GHdX>`-t!PqNW@i7)emVX6 zY5n@1pEKb6{$8!TWailjD&=rGnR{nWoE$2dF?AwS2$gG>OcybPQ0APH(iw^hkrHOi zkQfTh>Q#Pzuc_IoRG?iNPk^9eeM7A1RnFJ5ErgY8!;6Dcrb}KsB6C`4S*Dhns>KqF zKWmIk|Jsa6w0%-pA4?jrUz+_jbJ~oOYo`YhE@p;+skBUkkC%qZrWBXQYdS;nXlIX6 zJ(V|=(zL{Ipww!W6?cB7qL)6?%INX`hrRcXucFxh|7XuRDIisfbV5-P5di@a6$2yz z1VTwDVhJG$1PMtWsYZKQiAucCx;(yG`mW7v@=4z?-%JI2la^+4;U-!?+N-xY3 zIXxpwZ^sJaaXm?LW?caAyCCh52@94R*w z;|sFl{9QUfy|7U3&5H8kbPeojIQlPhFPxm45jSpp)_AErE7#u@ zM#%O0#KP!m$_?x2+zIJ9qcdBZ^W|tuo77Rh?zEdgUg`1YZw|f~YTG?UZg=&%?Qf)% zqCENh-oCcWM8ZXiI4~>KHsdNGbmkTayVsick_ zU0A5aX!E*d_y?WdGoQLJXszP(#y;IIP!6n&yzx1i{w#SfU{^FQQ?{dQ_;ksbEmv69 zCyU^h?C;V;x+bTlqzz0=>XX<#wO7Andjp#`C?zp1xoc{#!HH@8yQcR1&$&Z-CG<#4 zO&iiHIicT>6qD$mQsa{Ia?eX2U64_bKC*}#Ku!-M{nquDB|{F}LVuM@^Nr2Q9pAd5 zY;k?(Fg8!OcJBCIMOkCxCZ@|~v^#KmZk*ma%Em27&mASLs_Ak=ku|BcZ^|{4TC$$X z{~y%u*;yH5DF6Q!W&f5-bs4L@q$?V!3(i!9<~%w7@|c(XQg_>oapOnpnOQb&uH5D4 z=-PMf6~~5?Hq&f!Dv)!@KW5YOeqO%bOz4?kTDYKKw7mV|i?r14T~qvvL%zLhI6qfz z5;E=WW8wMfqtoPl;gx4*UhTJZTHmhyb^jQc)+;$RabQx{?ujSn_mX!CJP*lbWqgL7 zxv$Ie&;7cA?OT{6|D4_@Pfh~NoS&`dL%oFl-+7bA%jr(9NP2Mm-`Tnr$-a>#6` z8{MDeD8W@EN2)wgLg~9=9wGLW(b_mA6lP>+Wsa8v_y4twLH1ZY?>3>zntS z6YutQ%caXE9y?aw&`%s)lxT#`sXJt%P+xdyddal z$Zy({uLgP+)Q=&OB)zrqTh~8h<)_OsoSZc!eL~iWtlVgR?o$+ea&CPGTbM5wI+L0{ z!gQCtRWIUt5;cj18R_|1CdE(fFK76;LHWjy6J+C<#N15NQ{KgzK3OA+j3f=zdjaF8 zrO0ldQDo#kSKcxuPRhy{UnB+Prso%C=M~ANO+IaqoRUdq_sq)4H*Mrg*>>gv(_S9L z>1ZyLPy8-2UFGx6?k2$`%7;=t>RqmbQ|otz>E|x!Ov$wvw-% z>mrG(oF$)(O1w>elCezU?(%iv7KztNyhq|o=3EHwR~hN@zgf* z5x2yd9gLYR@vjn>NIXM6bKNTO>vooPk+`*d)o_Ev zk9HAXV`-qp62Cgkm`xHlA8t(K3i)z3T|NSrc=kwHPKh^W%U3-TYtOuUCC2y@69FNd8;uWOT2ZKlq{t_oHmal*%UcN+@|0>V)UMkBk@f{BtGhgCLj~Mfe#FdtNQ<}#&XFMm% zCGj<{NIlnhCSim84o2eVH%YrmeC6x%NQJ~x-je(hU%OS>L*kp>mT$HtZu_yUpTw;{ zk?kPy(9fhjBu@KLzA}|q`sOqyO}4`?Qm@3{9gy~s_`^f8JtV&Ru&lqt>Ay>RN_^E3 z`7yJ^L;jGjh9nLjldm*}%hwh1$#Sa1{fuXdBG$RGkYbzzO`p+ zj_^#(`Lb;#en8?*5?^E)5nA0N0lOL?bUJzwsmq(fCR?#N< zA^ATu#zZfUF_D(BCbC-o<$3nVcKN@iqKWL6|LT=ZXlP~Q6;?Kp_|uJ-db){yN8)cK zPOo9SNi|IDVflKfb4?SGAODyhwM?W+ZTSUfZ4;?*hWK@)sq2_fm%1kA!MY~YsGf<= zl<(Z;)HC4)^-aZyoFJw(Fi}S(&TnYKt>mk*{6;3UM&de+P57zCCR7q<%>FnN>eR%T zicL-E@}?%{U{m={rI`ucD98U7%}mUQ<|g!2a}(44OcUySmI;T>Hlbc}4!G%T6ZM1~ z`$Nt#p#|rd==m*8=>3)^oY2~YR<$-U@_WV55cxgOD{W1v|zMTp6zQCBK?M%~u)Uy|w$c-17aD&b!ruW6ht9hx3Z0uqp?_Fl1y2qQ)NAbq1 z)ZIkg(A`9e5=_(|2_|M`qKORaX(EGqnMlgzCbGD<34POBj)OiXs<@8{t(RkdWnU9I zJ=ugGPBu{oByKstMCZ#larX@{;iME}3Q|mHS&H#~OEKXG2gz~`GNH&|;|&~a!pDag z({iW@4IgT}r-qvFuwlkqCg+d$hnY~tD@}OyRmLP=Z9-pPZM+KCn8;^oa!yV+UafRF zM$%1WYlew^Cey@dZ?gTfj3@8~RMjjZ-F;S~>jJGYvgq!7>(6hNFW>B7q{E}~?lE+DVkCU&2#u?8Pn5ZKK#=E=F z#9lekcwbI5;cAnO*I}}W)Vbco+;_c+z4%`ya#OL1K6bN-q|PwWgJzn@+jp9nlzArF z%r~KJ^NsiSd=ox!xAC?wFrf?XH8F?pHC~-XCX~F`M7O@*nAP_iul*9)cmHj?u1ih$ zu?I|~+e60d_mFJYhfSo-BgVV_5fioiQ4_P}G2<01GtsG!8*kX-CX%<@M6X&d`_pn0 z)$s{q<~?DeK6pa5$ulMtx5C7%UTMNjo->g~t4*Zm8WXwo1zCr+ChAt{DZKxS#=Gl9 z*>10xsGnak-strvs@?|KPd1vETV6HZ&##)O)tgLA#%m_3-|MErPp`|d`MRlibc@V? z!-V?0X~O&8GSMC7JUD!-iTY@(?8k2#@56UY^wMo6=Hl(f%ieCHHg7l4ecv^a0q>hg zpASrQj}J}kyK=5P^s%Yf=Tl==eQKh*eP+DYJ57b_cN*{5P7`(6=O%jE=dzD|ZlYR# zVPZFbVL}h@GG_ZO6MO4daz6jsM9GiRLvMU-yf3~s;fddv(CTkY)S0`Dcgt@1LUp&~ z`&Ra`?@aW9?@VOc_oiah9uxD-9uwNX$AlOEXuKbPls5XwgtzWB=EzCTY&lPtNW53#KKo60+kV*(51OcUhvYasB<=LOi5?;6>e;`WaHl_vcdMMI zSN>>n(&&VCTj9A6JGn5@j}OCeU6)$`hUy0>u=+|__qmlFkWOr$n$20yr^#^ zZXS{IdBh7hmGk46C@-dQj2Au@Yf){%L`psORftN-&ou8R@e5z zXV#HxP#w>^wyqc3t)3U&U(fS8*Z0CR8+b7l8+u;-hF-W&BQNIbMxOU)BQHEM&I=_r z@uFunk@I;IFPz*|t{+Xk*yv_nC`qmvjhcJm2ha2(wOe@M=$2mOx>jCz?s>9|avhO7 zD7}UHpM^C8wM=6+BHoJlL&Uof|A=^Hip_r*d>nBs=AVwZ0pha|w?W()aRTCG#6uB} zK%9ek0^;BbufzP!h>H<#M?4Ghe8fu-FGKt(;@yb%AwGgQlxo+r65`s3;}Ew*+#Yck z#61xYM0^$Ek%;pVUx#=a;yH-#Mf@P*62z+!uSfhQ;`b4Mfp`z%gNTnIj+Xmh4b>3W zL);v3Ys8%pcSC$yysw$Ici8wHxkuFSiJVh3d@skehI%1e{+3QQo}Xmn5Atlh7jY=x zvbE%XZi?khIrnLhUuO8>+zdOPTnD@z`H{^8ITi_*7FoXnxCgirxHq^mcmTLQcqljy zoCa@|ML9w}9og#Sb&Ua{JfqQ}XfG-FC2$owtKkNnf0q+C%1@8wZgAaoHfe(ZGgMS0dZK5BJ zfaPaDe)tnCw~u}}22KSZ2g~iG4dd~mFfG2~W z0$&GS3BDe@8hitIE%;yHm%%rJH-c{hZw42G-vr+beg`}SyaPNH{2_Q6_*3vL;4i@P z5r!YW22Tfn2Yv?pBX|WkW1QW;SAzE<{aNs3V{Q5>@IItJ2i^}}4L%5d9()+Q2E6N9 zTiy%ckHBlezajsN;3MF5;N#$zz^6^HNdPn*MVL0W97eEajrxI zP4)P+G2N58vfuE8tdZ&CbBfG>ac$<-j897&mYh=5ww-jmI;to;&F^F~p>5&>Q@ou| zhk0`~S8A_dHe=@xPHx*KEiGfxr1TM^C$w#Qp}fwK?f}!Y%dxc4(tU2CDP9vbyxOU9 zw-d8)^eKecrAwXFfXUN#ve(;9dWys9wFAKcITYBW=WzL;A)&%Csf~KeCOOKRk z6Gj&ljZe=p#d9NCQ`)FWlhUO7y}~@{Y*YHBPMgq1l4Q_(ThrWHnn(I?%NUcEkv%4D z)OhJOT58Xn?Dx$&engsd3M@T|Br$58?uFL+$i?X}h8JeNLlR>&N?l!q7t5D|;J$Zf~f1_){a6e(tz&_pc@+WIo zb19Rhll!s#rIR^L&Mr+xC+J1l|CuRYn`lt3_8^@m{lAWvF5yI-WcRV&DMc5grL}F_ zZiIA$n1SAGdu1f2$h?f~^n$daf^_NeyH`eHqRhKUI^VOs-0O_Q3#H?|eCdckaqQUs zy`^g_DYn=SfJ>4SAtE*Epn|Dec=;D%8=Z`PUmVGE= zOrpQtxBL&v?A|tUVDFR;X}XNt{|DuzOTVBj@8gro%g-t6A*n}c;9yQoOKp>u+BPjw zHdIQ-G^yeuf01|DDpHCrl70%c7wMub|JXa?`R7#aI<}xFt)M7Z*RMF_&m3`GRzaTf zjF2AZ{#hI6gse0j-6G!~vOzM;wSu13rQk`Ui`2UJgf&9OxyVh+&`u0BW$B5O3@I>e zy!3ybFDDKey+Kl!ok$%i!%v)C(=#U${nLpGYi#ZQ!LGdC@`>w&_NuE1TWms6o{YpH zR|%Q3UFW2akYPELK33A*M$UuM38&22rE@ZJr04L=(Y~-pXJqE2XJ-1i-=d#G^B=KX zx+ukAKf81(>o@ESi-nW@U45?7$Wr%SADMNjlJpFnEsIx}mm__4`aP>_CCf^aw6Asl zRI8VGO?t*A>4{r$jgMJlGsfmCt|#VCR@?&Ao?n%>D{K9-uFZQT_e)6Z*k0#s~vj`l0u+xW@Wk@n>$7w+?5@L7JF@^Sv5aV2;u)Y^n{-jv0CU-HrHqCH7i47H zy$CG*`1)CO=_9j>Cd&NwXgxv8lzNy_+df3k$ongnL_@#E=^!z^Q zljYbwT03mskdi}%GVWil*EvOtZT_x_q~Nt!J8P4a4RWsV6Eu)0WQxP|VE{+q1BFt3r->y@A^uw^`q4 zw2Xw~kK=z_wc490t8`&IYTH}<-V@KrWmAkIvRT$VZ01P6Hlf@h1=9I9YrG>$H;_L} z$6s~AW|4GkXiB7en^2Ki9hECdvKPvb6>?WDJ?D;)dvLS1hN+rho{mm2UsjTLE+>ud zV-{BKYo4oYThrWLHQBs+x-(eEgEdmk`Wi{*mzw>};kw<;>iRwUrzB(*7IDyyC2@&4 z(gSf;W~!XR%!;Oi&GKe_q`&g<+Ijtg<|Zr~&1{bzZ5A{>VI}oVk*;-Rpq{mjO|)!M zZJk1MKyv*SJ<{A#A=BJZVS-s$VT9RGK?acRCu_J(I_!zgGOJ^<&E1tU%wu)z=mAl(PlYT6V%=VbvO!TUsnum>cq=BiBVAjTB^V}7j9j?}dmcC)!rlG)MN-($ExnALGz%{@(Q zQ~Vff2e8S?ENz7Kr)rtajZM^OQ(R%BnI+9JUz%f?G{@y zuQbm|_d}u4<{`=cyksen-iHKN3a%4eEB#rT%|m4JzVu{ic3mNpebS*&OoDl?A`eWi zP@#;o^m-*}R*o(8UM1ToX6os3)cWs`K5bO*!~~tC+9nQ2$8N#_XD#>Az=MS6BKA#Ryww@o9zf z4#z(l%<4)`=g2$HG|>s>;A#J{LgsCEbw1(h%sl-R3%@P6@LK~5Kev**@Ec^|9~dqR z&m~$>X?&3k`IBq+uR`;HoZhCUOM5RYGBOI?&7Mq`P1EV|Tm08Eb^57vIukMbZkH}+ zLUN&%i`TD}PP}D&Pr79Fhwi$)@<}6d-BmeaR^FlJ0hvlys&*K!$16*Z^iNCLCK8}IZyl(bI@xpkiC(KtSy ztRlUP7p3RQJ=MpxYxm^Zo^SBeKll<`MJeJkOIIYE6}hx#MnK5V^GG zO*T8Kj2J)49H=+S%s$iLRBmprT3Y%SQhISCr}WR7+A{x?GGDw$*Xz-RT3qRnUr$#( zF@V8{pJ7T0bXgTzVS( zJ1%0jf2odq4szsl|Kj8y>xHR#_FQ2$)|D$4u80R4`PWW=%&1w?YcbA3i)-NAeP08X zteY&y+|opL-mi4Q9{gITtG?0cz4wJ=`lLVIC{x*<{J9M^o&sWMJSVb1uBtlXl6^nx+n z@+O(jYvO|RO-*|-Hb2zlQk!i}Fl2##ge;OSPorhtJTX{=~3hcT1Pi>4kD%fMwcIOYT#q){U6` zesy2|TdRKdL2V;@kjn@oJTS~HwPmi z(8&X;ZIv5t9aO_PrM)2qEz+#v39`rd*VEtYpLdkUxZxnORRp=qU6r$)CtIiC28N^OJ@tG!NJF_rncx zURmMS^Na85AVB7=dh!XT-kRdfs)PxW|Cn$?guQ)ZVe`W>%p<+252)Vcy` zB%9yA&$_EV_Tt5|kaz5teBq?Lf?oa2GxfVoHcJ~6`gh?A8b-{nLt2PifWMd@*Pkqd zrQxW2Ube;jU$uo^{Y|HT9MS1lN7cka&S=oJm(*b22D~BXnlGdq_=uS|B`nh={&by8 zCBJ^m`&@(4(VEPQ(jc4s4DZUQ;xaJ(OwA^vI+&debWALJ4m5YlFbzDQ4mL=U(})bP zY95wNzhky)pUu(fZ88+R%<-pdWw2^FSnk&8(RDg~=p`*$-+!!X$ah$u$+G^uUg!It zPx|fhQA2;E9aeptRINLc+1oHhk12oDvF~I9tlbp$hRFCVd`q%cdXd-C=QU#KUrFhI z$l$#ur0*;+j8UOk)u{CL_TIRNS-wS=?yt9Xx_O&U4{g`!k$1zMy{-OKYWrn}&fD{z zPLF<|(>HhN^hp(xJ2I6sR=$j#>fBVXYFyxdf<4)MDJ}SopYw=6 zz5Qz~;X!};yi84q??(P?Tsle*_icZ`Fd6#Gd?0<~`}@u8xIXDcedOk1UYuNc{ZhX7 zr+@op`ET@=$C+m&b^bS6)8qd1JDJLHBp*lVdxNe;W@ntax=y#w(&;C+MWpOr8F~6Xdu)mf z5LskyZ`vn)gj{g%l7nWSq{}9~U8m2@(dpa%^jm-Wmp`5RfX;u!pRVwya~{+=8y?c> z;}7d}=c78E`J_%4t<~wX{&b5><=`zUk_MmFOh0`zPsts*eam-mGk%S;M7HtgR(MI} zH#ewezmt*^oV;PpC>U)&<$SxD9S%^=Kyv2zQZmXxyiuo5Y*OjO0dS<5-W$kir_fB3 ztR=5$rnmg*Yn%1;t#9dcu|GZJPiJh^Ip4jl(|h01=_-G^a=X5s{h>}*`_p+J>Fd8g z(JJ+wy`JvPp5_?nWux2*9NnoorhlQ+&4+aQ+;2Ml?RT9PA5$~6V0>0;UP9KWzPOh+ ztIy<1f4*ig>!h@$l3z;jr*9sMcwKemJF{I<7XGa%PZUSVbmtVE9-JB_pY~i-t=Yvt zgifn8->ci8%A~u!>Tw0tizZI-^ly$g+q3`kyaysZ>c3r~=5=S>aK;TuuY2-$@p^AY z=qImR<_$?Li@h0MZkKKo$FK7edJbRU#lNg^LHsg}rg`y~rCfGdLc$iWN5_&-iFes? zFaEyJC*BV42`~S;>y~=|_VTl{26Ve@Q2agK_`AG>;SYN$Q@otF!b`lTLvMti3f~#Z zpYJ^v$v@)V;=SN4i#qBZ_udHg=#?6uoG^U&Jg@Kb-jr}s%aU-bj>+yMxmCxKa89dk z1JB+Op5}GCwqnZe$Zl_n*QjE}ii;w3>t%LGY8K`; zh0DFKz396`i7kg-)qPuq8y1A;hCU1ZlA9Gc}#=sw-6U%CF9;kU!DdN-`_ri6Y7 zWxwG)DXlVb^2EhnjlaAXy#?OG(i9UjWQAmnbgC;>tJWC}D!%D0@@mz&X1X^m`lxr* zn-$gclTh{?uk*x<`(ArS_r%td7JCUJOT3=(tyX)3hbQ%@wa~jPPg|w`3fU+*`@EZF zi^Z3OlciN#bsSi$($&v;+5HmYhfnopM~3vccu%x$gXC6S>Pvk;g*JE_LbWcK;@u-& zkY4Vl`0MTKjrmW75?07dDU9)S=o0E%bs?hm)LUnCCTyayL=s5;&thn z^ik)oz~AA3)EakXk~3*GEhUlCg1)!7?rpOlr@@;8Dneb9mVtOhnc zyN%7i72Lmr-zonRe1Qa$lc|O{GgL*Ke%p#U>eCG0yrc z!6U#r=97jQaW=gO{E)EvOTb&3SZ>rsbIUkXO)cwKQ5t@e?X3B0US|21=C-_n;D=?q zY5IKd@4~u1r^Va+b!59~`Xya0UjZ%#-v!$TbIyziW^jWqS_49hPg z|M%eEk=|gWO+P~h2GII+j4=(JgtfkDqb%ouD`Z<<4%V^AG`tPgG08OS1?$*k8cuI* z+p7c}s9!Fu^<9Dv)c=L_x!^V6M)}tN9XtXo1Kaw`=b=OOQQ$S;5plMB9Scpvj5y21 z;AwvTVzV5)9y}Nwtp5R?0#20knC`D@z;}V8C;G*k_rNPBS*|7nC20OHz{9~cC)@Ou z;1S@T!Bwue>1VdHerIq#I3N5H_+{`>@U{Q4zK&z%FE993@NV$?;CeUO{8if9{F`sG zJPh2f*z%p=YrvoRY|K)y3}WbSkAvV_z;$o7{vPm8Q!Ix%+WdJ_EjIFBYr#{&Mc^gi8^OPV7tXTf z_2^{FUkP65bFn|xp5}NJ+~zi$pZlkd!KZ=y=W_57^ zyZ*6rZ2B$W=HRD=b^YVPdyvj?U1Bb_{-!&upCGLHU%k_EI=JRM%Qt~_>_81%pKIn@ z=K4Ggz8~dt{Frs{U%b!e{|NjZ_*dkQTWr(0el5YR<+`fNr(+aq;P!5@#BzU0*Zo1q zF4V9L`Fk(*(YyoJF$^{QjQl#5p@w#sT3^RB)G$L>>-&6_<)uj1u?{snkMwHKTYeY( zCHNQcPv8n&Y1 z?efHLv3wTz<2Nn$0qdBO8pg$I{$j&%g%*LY-Kwc4_E#NqQUmwbP2gYSt-lZ4v8&x5 zlHT#Nn_1uo!3Tx4zHh;4a-XF8->Ua){&m8d-sXMF=XJNd`2))jfIs}ua-9U5u47?p zmM zHE??+fuHm97n^+WabaDb(($Q!T3&y^`sv`EV4gpoIcU>gLb{G2s)5%R9ZOV0-ClP6 zW*@hl01p3cc`R7R7}YQXd>i;7@ULL*PnBf2L=9YD9h+3cj5xdeG7O^6uls(n*$8fM zx!oUh3{wrGz#oEN5Z3nKI9(qiy;a!eui4xBMc_f;Rp5Ex1v0jthL6B|!S(uBe;&pp zy;4}~n;vcRPxRA`xm(6m)vySxW2|a;0sewm%U)kw-lyOmKFj++8G}_rE?CE8)o>43 z$7a>A5nSsu%b)pNY}SJtC)@Ikj{7Ge4O~*$@(S>uV6UIe-$qwTLIQYaRm;=BvDGYp z1nvTE)!+J)PPge}!0W(|f{%f}@!9xe%xZm61JpO>r&`uO)8}H-t+wT>!JEL`e{^hG z4cvbUz!Q;wF?a>IX9Ju6FYp3z`+;`(H-dS7Fb!?~8~t=+W;V9W<7s{q%l9F@;aQfS z5!R+W25y*Qx#HP2{U%{OUrqz>_F3NNw6N)3s%?++TUu`DbFt~u%JS_<*Rgjsusw9l zT@7rH@4!#Puhzz<*BE5$&j)V>mw>Aew&{O@UjcV+YyG-IYXE>IbPq-;5ipr z|E#NR`f~6U;5Fb?!n!}|*u@&&^|{y#ywvjf*Vy{&#akW*=6FT3z!SRL^qt`4;HhcW z-w)>Y(=n1YaQoc{K8XCAz;lLM|C&UbzjC@|9a~w$PvF`~md_ty(+7jS47>gu$FPa8 zu5areHvc@Ii~TX0wY*uGHvO#LHvOp2#s1jMntmwDmOrbXP3QXPn9drwKHq^8M@sz> zgLT|<4Yz}J{BsTe2J1NJ8did12U~s(+yeYDxF`50a5nfj zcm}xoD7(DNz|Fy1z!!q|fG-F8 zqrf_jyN2t)I-a|R+rc`nyN0D;9p7EUvtS+PUBhOuj`yzN6R?i^u3;}&$A8zr{Xxfp z*TDTj$Aj0v?V;nsYd8*H$A{NYeY9;49VcD`_eUKsUIX_B9XDPB>(}w)HE@5{apW~L zLwP!$yatx1lN^UG{7*LN|P>r(>e{5guOy#Og6DuaKJJ5Hj<>rOd<6O55!UjmO||8Hjr9HU!%shqvE_5z z!A8oJjftCO(>n-P5pE7nLwXBvF49|pry#uzcow)l_#SX4@I%T~Ayazl6Y;Lpdb1%3Kcq_OK_i0;G^LF;P6c`Sd873OSj%%+%j5Uw zH=sN+{nM;ox;`$e&+psk!za_P6!2YEpWn}yz$eq6AMjmPpWo+ig-@nmH{iRhKEMCp z1E2ig{Kz=@setqTr8b!FUs?#qp>B;X3vhCPhX;6kfOUB?b%GE)er8C1_jp<;e5&Jz zzi+5iVD~@r9m1#Df2yE9tvXpIE^GT$Im>3KRA|d1HxzcuyC=Xki%w40@|(;5BwJkR z{^qjQ$KPYj5nqpg^0)s-d9woLxvb^YKig)=9B<1bb9t%b^{1NcU^rcx(s^4YxySK3E`S8i~ zCkA|%)n5z$M)+jR)n>%`h82nZ8?JvdnZ@{b%9d2cJyetxtWI)$h>K*1rrs znZ8@!sp>C*zZyQ7{+z)2yR7whKG$Y=4L+Iv?11mG`kUdu51&lmtxuQVW%W~A*$Tda zPp0qIr@qVT?}C32KAFB-->K@)Jr64=4Xx(`GW~gh^>{yl>%?>E96WT~?pJ=ku<&>tD*^>H53%>GHd* zK7aq$06w{__4D_Fo#2z{Ck2+@Wv!pTFB}S=O#k(O@3Q**J>n$zWcqG>y8bS!&)+ZJ z3!hBitxtWI)#vXW*T5&!zc{e`F00SqM}7pKOn-gAcUk?qoo$BS;FDuyM>*B;jIRSr z&krtZdHj9mbn*3gB6E3u3M`My>ht%UkH9C>?-uY~R-eEBEc}F-5v zv_5&Q@TuCvJ)V-qcUjBh?@hbiWXmIG3!kbycmLAzT-NgVd(}NCk1R?4@ruiJ>GpA1 zeg3{RTx^$zOkZaEL0RiBw&<6qK7S9}>SpVcHGgyYpW)yzns3HUCn&)?_vlg8Kj$@DJ^_%5r@-}6Rpu|App#DMRz`lrR)3`5|P z>E{G|@+8Tx@8|e^(=0H*Z(0oI_f1cM`F+y{a4f$6c^}*Y{5`lQ_)l;)xbm&G{u$sn z@G|fP;4R=J@E-6LV1D0}18#-yhi(G%`=)u|*+_o`TmoJL-U@yTychfhnBO-Y0Q38% z$aK3t{J!Z7Fu!kV3Fh}rmkP&W+h}yTrdK`jdE6CXejax%n4iZ@2J`bc-QJlxK?uHI zo+bG+nJDqS!uo#saNzT%;&_`WRt_}XpUGOZ9*^s6a_RZNW!)by>1s1Hg-@oR5b#}A zzZiZ7>j%^C8Sq_Je+%;851&kbc))jA{T8?Y?1WFIzaZedtUiBFe*`|6etf`pS^eXv zzr#%1{$%+=kNCi!za^s+dElix~x8DEP_v_@3y!4F00Sy13rOIrawHe{4T4% z3=7m?mR)}`efRSKt>0z!`8>j<@X7S!1NFPC{;))w;YRpm`pW{o%j)y_hXwG-^xgK> z<#$bhd@_Bvz14SFeLi1N^)}mnWctGc%kQ%K`;u&izVONPrv-eM)#vjZqu`V2 z#|M0u)nD1eW_SobnZA4dOqQ80tA7CgYWQUO^0Om9D68+X`Uz;zcj1%iyY-!_{;BZy z!zY*3-w6LS`QSj$zhwIE{-X7}tjizW%dTG&_~f$sm&3mlKAHX&TYTyH-({_z&+qhu zPo|H}Q|h~{KA-ow4L+HE$3XoqtAEGkHp2$^Wcsc2g#?X~W#Y2>FZTA6%?I$wn!maH zm)PV|-(~gre9|8HWcvSY|9P~Jt)SuUcKeg*9}m>;vewV%q1wYI(~l4ME~~%0ugy>h zpG?1=zL20%vP@i7|9G;WY-YhHYkqCNPi%6j@3Q*(J4+1@z$eq+VUtUJm(_o~zs;}~ zKAHX#0pDfyQwP`#@4+Y2m#btCdmw~qY@Ep7S$z}D| zz;6JbOn<2@zO?;Z*7}FygxDTFnf|{6zRT+W4!;k4GJUtbbp2gce^jci;2QX3`q_c{ zT~>b^{37^d`dIC4wfeo#)9iOcFgHpHe6hfk(|mrX8RewWqf^P=P7lj*zHTdm(^^-G^Gg-@nGJW#*O z>hpQjKj4$;KOFE~R-ezW)|zYEpG+TzXX*O8tUjN2O@mLSKP6DV%j)y_*xB&O^m78f z%j)xa+O6=(^xx7K5;RJdiOcHq`P&2V$(p~p{4bGz4fI`BpU>+yzSFiJnLd7AUh2E7 zKA-RH2A@p-4SnI%@3Q*Mhx^H9GJNtP;b}I>pR&BC0_C}^vM*BKTFp9x;^Fxe3#Yd^UW8+C)4i`vIQt>{VuD|=b`iA zlj*z5tG>(X^ZDty@X7R#1eV`r_4&N@3ixFD^0Am7l(l}B)#vls-@+%;e<9$ztUjOT zZYC!>|NR6mnDmzg+RtV6`TTbhd@}u`f%;umpU;bD!6(yq?_ZN;rpxNfKmmTZ4L+HE zFMT0FBlTTYpU;C7y|4`p$^$+DrCJ7(GC)3B^`f{=iz^bPo|IC zl~Uhj_4)jKoE#Xs{mAs=o%(e7T~>d4p3QJ2d@}vyfbX*Ud|rPnd@}unfbX*Ue7?T~ zKAHaTfbX*U8*xDX0H0h|zv(zz!BO~R`f^zLK{;6_E^Ga(;8(fZwm+GE-+=G3`s~l3 z1$;97=L5dW>a+iYE8&yrU#Bl5Xr#;Uvij^VVG?|@=GXlnANQ2{F00S}6_&s!({Cwd zXi(PrT~?p{F}whuOdmhDEcIPhpZz!d3ZG2Bm0$ab`dwC^{XMi^V7DKce#e0Cvij^F z;yUbtBy``Z`>pG@Cf zU-ey9pZ#+@0-sFZU0?NGR-gTO9E4A%@2;=rbZd)_1D<*U0zQ8j9hQ z>AUTvzROxa`xki;KAFDTUh2E7KKmo7aGza%GJSV_)puEa_FvK+KAC=wUA@xths)}> zE4CT#fKR6HuCLbbvijG+-wdBj-(6qz$<-Fw?*sWfSu-%7C+i62^JKlie4gwoFrO#O z1M_*ZDPTTNb~l*MlPv@Dd9oM5e4gwb<;t>6@O;A&;W*n={xo*+$$UnD&kb;g0AD7o z-)F|n)|Qg*#ld_&K<8%KBtJd)ePyQP&-7F5WTNn?e&4&a*rxB5biF?!Ytedr8)%bD z_YaqK`yMQ|8M@tXeKP&C1HQ}Z*S*zy=`gM&B%DVn8tIz(P&VInQKUwoPm;ZWJFFl@IR)6a(n_)71 zGX2be@3Q*rPwFA~WcnQfzRT*f|EZ7Rlj$c0e3#W{e^tlflj*k%_%5r@{;ldhXxooW z|Av6?vij@~s{}ro{-l8Kvij^ltM)^-elq?30iS$>djz2U#<21)Aj8W$aRj{p^pgJA5+zc>$k1Lh{EU zO{3cbyf(mE-aobXKFRO4_g})NYH#)znERMrUow}sK9)&2Stc&)`hF?jTWNR#KAC>1 zzL21i`Yx+~!JU4xc?CXM^Ea3Oxi-1fcUk>c;lB@`On*SYcUgV*hj;)!xvW0>PprDk zwjY`PefmOzM!NnkYyE%A=foP$gHP7{y8daJD1pAq>a)MbB=}_dNmeiQT~?p{JLbSA z(|51;y8JGy&;B5%!za^kAE=-FsN~n{FZ&}|17?3DZz{|CNj^`m<^9wCzEkqM`}_C8 zr`q4E-E9{r^>Mqs$Xwndf#r2s*Ee>7%`gT&nZ7KtAC$GdTvq=K_{H$a^eYB@m(_0q ze*t`QS^ab2KMtQxQ zR(}-yi{O*X>W_ne1$;97+JXJYW!-A;ok(GTvmS({5#;2%j!P@ z|6%y#XN9L>*)?K$FNW<*1S-- zKAAqc_bK&VR-gTc4}edmzb#O|%j&bg@iFkp^eY8?m(^$ghb_1XXZO88{@?)_J?%ye0O_Lsj6KAFCI{Z`*)_1VAvUijp) z`s|Ot!V0_pkm>getiQ`zKl|@*0H0h|pZ)!}gHNX4J5ayNTK`us*$lnmlj-*e_%5r@ z@deW1lj$!G_%5r@@d$2&Pp02D;Jd6o$1hk2pIlb|npbQE&%r0t-xa9eWv#!)=Inok~M#G`FF23>btCd zBlu0>lj*zPU#jo2`j^0O51&jQm;ci9m&@uWz)yltroT>KNYF^@cUgUoUvU+DvL@;J z50HNi^j%hez^gWW0(>(4k@`XceV5gLev?hV6F!;#qJZzR`U5vx|6%xK`ju^RY5gv% z&+$5*hfk(|Ea1DW{*|xW3?IQK)BiT$yR3fv7Mo!|d@_Cae3dLST~_}#_*I^@`!AWk zd%jZNW%YN!Zv>xAe@|ffT~>eX8#Y6G_++f8b4M7Q!R-J3dNBLH zp95z9_YVliVcTi+LV(}a{Bm>1{>{G%r2i4%%Ii)p@5}&SB&@$*W&h)S1L@ajdR6Hk z1HV7b2M-6|2rdRM0kgkp-5)Y_f)MT1cK$wY}a3ZLrxMUKDK<|Vtok+o<&Uh1O^ zW!>Lg*8TPRFKmV!_+HKAHXvRxkBkR)6w0 zHbbqK?e-(nm$y}ZP}b#lS^bu~ZTea8$@D||LV`x>yR1IPW4jbSS@Y}qkJc9wG*aJX z^*MgqH27rAuYR`tYoPD4`hR_A(^tVK)5q;?sqeD-n{h+?9(*$WCvEYizRT(t;)eQr z_+e^_5g&`9fdS$&RAxC=g6ll1sWl79{KT~?pt z8Ah+S`wy9ZOO++icUgUof7oQb^~v+KnmKU4BBv=Bbk_4e}p zHpe1K*W;BeFa7OR3k4|a`ns&`l?MOm4b~@Xe%;<~{!{ry@HfIIm(`yM|8w}{vieKl z{|=u_zfNHNUDowq4L@e1U4L>}{deHkgHNXa-`ejR_~*kXm(@Q4zZZORS^dffYy)M% zCzsW43jZefW_l|8hmnD{hQ$Lgiogb-?smJ z_`kp>m(_n9enq(v)Z?FA7XP2lKTV`O_x#gZ_*Cbg^{D@T)K6yp4FboX%ewtIe(i4f zWcn2YzRT)=hx+3;+4U#We>32_tUkxf9SomLe{R5cS^eIJY=$S{lj;Ar?LQp;Yw*eR z-TggTX1c8PPlEpid@}uO0?Y5R`X9nS0G~{Mdcb#C{i_e#3>9Cq?N6p33EOmKU4EC< z=lH}8;gjhf4b<`$8Cmw z@X7Q$2Yi>+=lIiE@X7Su`#W8Jm(}NZ)pOyK>0cbE-(~eVzV!?6$@KdMe3#Ydc-Zg5 zC)2++;Jd6o$It!+KAC>yfbX*U9B;eE>vsPk)9)VeT~?ptb6*diOg}N;yR1IP^L_w6 znSRTF@3Q(F|9c&LGW|&b-(~eVUU>B_cKylp7YBTo)#v!)SHUOKPYC!ftIzSspMp=O zpAqoMZ%Kar{F38geh%h%n7@EI9;PQBG-!T~hglQM@i5N@b3Dw>V2+2`7tHZ6hl4pD zW+9m4Vcsenhh^7jPJkB$_^|*#9pDWC*7o_Q`;T`ef2LFaXTqnt|0u=>NIl-P+n>z# zFF_f~$ue4Uqg-@p6%1=G+-wS^nd@}vv0pDfy`$TC@X$SaZ`bmE3 ziS>6`{dw@;g-@p6BjCHN{wMHH-)h^BO#i>#zwLwH1U{Mm!a)5lYyH!sHK&XN2%k*< zvViZh`kUboflsEN7w}zHze9}Xl+RJ&lj*zno5?cMW%c{QpA4T|RzC~=ZScuu_5THb z34C%{{k!3>hEJy7KhS-v8S|5Ny6`YQsy%jz${05C`3lj*zH8*P7=)&CTJ{M&Z_ zCDR`ssNZGvJ6F)0GR_`+GW{Gs^~CY#vigt0e-b{K{=R_kvikEYYEHQh!za_fIpDjj zey!6qr!3z)cKu6P<~5i9Cp1xl=1P`{%j&O(Uk^T6^Q#{({~GAW`(#;tQ%NWC93p%& z{Sup8>btCdNoAX134AjBWWV$i^}DS8pYZp?C)4j3@Lg8FO%=^4>$%OgADO{ScVreXj;{yze)J<4~7I9|TyJ=b!F(_DcRt$Nx+CRQEe`vA+55+Vv%K zegE6_>Jj+U;FIZB!ZIjpd%LXdy#oHd@X7SA4)`vsUj-emu7OXc|7^f_S^W+0-+@o2 zpB?aBR{xySHK%-T1fNX5U%+=+{Ymg+ci8qP(@zNaE~~!|eh>I$`tbqZW%ZB2p8}su ze|W%mS^cYOXij5ZflsDC)lWTfzHwRoFX4X;pG@Bid|u+R`aj_ZYmxVC`;qAn3Dobh z`rT@4PI2Lr>AUxL$uiSr^=HDr3O<>>`}u(SE~~!@ej$7^{p_$^0cG`FR=-s}O_BZ$ z;FEQ3bNP4gZ`F5M{Q~&U!Y9*jsf9~WR^Mgy7sG!CKAFCIeplaR^?NqZoO0fN-)=uL zefRpLzRT(_fS(GVOy9jesPD4+8{yvupG@DqKB!OrK=SMPK0aM@%Ji2|y7(ThI{?+g+erVU9On;2Nkf4z+zsp+x zmPR&1Q}|?^tL?Wz{xvA8@3Q(c8*7UE&K^El=c?b;CYSmytN&)4%`g-`nZDazTEENc ze+hpKd@}tDbm1f@tM9V&ktAB1& z%_;pv!za_fIpDjjehK`jkL>m*({CK`T~_}s_;K*b^sfu}E~}r|OmoWTZt%(Uy9Tab zE~|g*nbsc&pG?1YpnjLtUkpD3KAHZIfbX*Uhu{~%C)0QLw`7^=vih-SX-?^P9X`3N zena>R;FIag$8>&B*7{x6`oDu;0-sFZZ7=m*R{t3Mb@0jbs|4zIS^bJ>*KPPcRk9xALWtP{vYM7(t;$gJeRe+^IO^s9X_?oN7lJ|e*0Wy z3G`i7ztXwZ9{`_B-@PBw^>JDKj_^moC)2;mR$p4b%j(aAKOR1r{@Q@=vif~mX-?^9 z1U{MmvjN{__5X(NeP-LQl*QBbn-TC`R)6|=w*JQO$*liyz;{{w>vbZbD||A2_j-~n zGhJ3S1_O+wz$eqcFHpbB>OTNK3qF~?`~8*H@3Q*e!M_bYnZCQfsPD4+)!JxI`CJS> znf`D;^~C<`vikY(EAF)0k4*oPfbX*UCGcN`Po|$7@Lg8_Px!HNVCnrSnSOl0cUk?; zZ8fL-t_nVxetSRl#QM9eelGlKU)cJ|^t%Lnm;LpJ{{#FIF#QqwLV`xgGI3e`Di_!c z9lo^nlXb2hKTG6agR=TA`}M>B5`GDozPr5YyR80?$e+2()=#G2Q!AICtiH?Yw`;E{ z(*C=wPu97*{8{p^L0Ns5)xQV+`CnO|tohZyIPm_~W%YMls5#|#@bJm>-S@Lvzsu^^ z>7+U3Ip(iz{bc$De(H(kcUk>e@V|ghrth}5*6*_VTi|c}#@0`!zd2ApdAH>Ezn@Ll zoW}eHE&*5AZPV9*8-VwM&j;7U4%rRd96Siz37oB5NzOM@ZGATg$N4qe$*r0$?_c-h z{p*9|5}SVoIQB`)8^Lj4o%>Jkci)%%nNEGXg-`W)<(!Lb`KjO9_9W}v=JMYFWhm?R za9Ov|9HU4AnCJbfWSBVB%%wf+tl+YGJXlXb4H z{|5Qjpsc>j>i-763w*NXSAUxPYfx6-W%aMSL{nrOD)?lbtG?Vu`axNJm(?G5siw$v z2|iips{fQGN>EncW%c<$-8=Bf^y4Ip2KsS6Syn#|59IBEPp0p_ztQ?#R=)%M(D$;u z4wu!x9DW1%WcvN|g#?YXewVfWg_qe3t>BY&uD0LJ@~=TzeV5g*7q2ODKLwwxbJee| zi4v66cUk>&;pf07)5qnp)OT6^tGa4V=_d(3nf?Ml^+f$HtA7yw9q`HY>jZq4)vwr1 zbINnO@X7RZY;x)HyR80%?l!{?_+-(~d&C1_5$ulm8(Po|$3sNZGv?}I-aKAFCI|El%7to|nW*TW~%ckjQ|cUk>w z5;dpv`}w0?elmUc`m4Un>Mw@B06v-ib%FJFS^e5cnp1wK^OLQgOh4XFJ+c3~to~s5 zYv7aVyUTm3<)06K)?QmbnZDaz>XVmCe!ZXQiR=A3a5i`wcoO();W(^|AN_nXHwy42 z!g_zu3D^5x;Qrt%!P#ZJ9~dq9GoAV;3!mzKpmh&jb7Ovx^yc!CJZ#^IYnP^LE&w!DzALjJWp_BXl-%;zQL<3&H6&p*oM^_kDJMvLqFvYs01g86x# zehj4P{C-0(1Iqlq;%YEIe;W&C|DQL4`Tfd#Fh9?F1YE6|t$z)ezyE&=%;%AIfjJ)H zL2#oD){n>r(dFakU1xy#{rq`g_HVAAi)()V-f|Fl>@Hhg7MSVd;29|_LsGSK5mF!1GB&CkHPG}`4E`>A=i*&OWU_sGh1IvFn^za37Ee(91P~~ z|FXdxKVcG>_kT0N9G_t!nBzS>2WJ00TflstcPE(rYwiQHzn-WlyZr2*xF(q2*R%rj z`TA~Pex9BJu5y-L|4cBSFT4rN=LHvn`TXDG-~{a7uYlPf)u&+gPxuR%{S8E-?eg>c ziJD-J2hs+dfDd5$fv1A61+)LcX<+`|=3em2I3GO;-qp&k?~CAP^+YJ)4e;6)mOlb- zga0jf^SL(tFt`LK>~M@-A3h)07|id#E&}uWxKuEoN6ZED_eN8|d|vM!FrPnt0?hF@ zHiG$l+9zN>?{*l>@k(Q2?eg;btvX=7e{2Wd*we0WPjEEOFPY%evHiz^`F!UzFrRn5 z2h8W6o&j_G)s0~G$M!y${XHK5v;XC)73}h}|FWiFeqY)ie4vM2{(j(<;1OVczdIhx z@nmiRvwzD+!Tdh)c`(0U{s6qYudQz{_@jQ7qbl0v-88^*Bk-DmmOFx9A7r^VnEi`g z3BGc$O&O&c{7u2^ z-@QGU-$x{Y`F?&dnD5WWfH{87zrcL|Iv33T^Ou78`|+p2{5|sPVD^{)HMm2Joa7}O z1ZRPxD%thn@2SrKb3B@s;PH6F&$3~op{3=0;7iW2d<@*Zh2@G>?fRs)vRoJ3`CQ8_zB z`&&*1cft8+6nIpsP5&2oXo}^#!R>LrdKMgw^V1gaHu&FyZ$bV)z*F1U@?xvo<>h!M z4Z-~V)dgVwo+<(SXdmle3FhZ#W5LT3Z2BB9zppI;H$nYdz%6h*?FRGrtI?<1<>Pqm z4Z!=7Z229*bvs+`0lo|8j|}kdXut8`)B!gCY%s?oTLNZ({jUkjk!lZCQML#8rvU#I z;A%Ba_Rk4$Ps?(bX2Vd+a@T3Y;{pC5z%6U~<(KA92=LVbek{O;0vs=ISY>5P%bOkG zF9LjS?UVBt1^A@^*FEF^WA8lxn>d!oVY$*<=-rgiu_d`v-DF$1DV8x{ijd{AEi6k$ z#RUj0Kxm-^2rZ!|^xh%#7D@`egc4dv=)ESuH@kZ$o$e&r7y|G2|HOM2dHe3{?Ck99 z?2L8(7C1cE++GMLJ%baT$O$jxlwZjSZy@>2@ZHM^|3bp%_W$CfKjEa81VJtvKJ__a ze@CC!E6x59frZbHWQb;jNtTFP!ixPWTT_ z_zoxhgcE+n347GChF5t`xH>27#R)g#gvFe29pG>3!dDNz`tW(d*8skT@HK+3F?^rG zhwfyX!Pgu<#G|!@uN8c);q!*i2R z96kwrk?=*q7Y&~jzE1GPz!wW2;`!p?OMve)_!8lh!jGa__`1QD0$+Fd zdcfBczFzPt;Oh+^;ulllQ^A)89|d1Jd>Qa%!Uz9Cn!>LbK7aVa;ERAy2A>)}C%mlT zux)>a;RFWnc=^IdOa<1yvcC)<}wk0TK-{R?kU>7^*;S)a$aWizR4P<_PGQ zPD9|sbjGALhN|@{y)vBvpAMqvL8zIj3`ddCIwLe;?k>d0G$t4q6Qid9KvvTkj-w(q z>WoZdtWK9hH;QAWT7yw(=^KuVQ|81f3n+TdNofRQb~%||m&yzX7a}OY&O%}&`E;B~ zZ_w#2(2Af^O&L*?G2EorQ_L9R0cl8foD6UTvH)8sSh3v?5jM zw6Kb^<(U*kqavLWt4yUdbhjaIyeT`CK@pTAA+-;sGSWzhBCIA4!by6i)}S$|V6r2W z`m8V=jTjOw0#+noEl?FwKZ#a>LPq=Fo}+bAhkX)lH3w=_{Z{B_>v`&d{FXsXBVDq9`o}5>2+rw9%k~<%h^8ARtiq zFd!~zhA53LRcS8DOHPoJrnw7Os!i8fQVLWWij5zTn}#6*mZfnNnQAVELiDCW7oc|u zI;6JBnQNVx%Swgitp?!1!m{24P(83Ys$j4MXiWf~u=>KJaJD>L$dID}f|$muPNGrf z7^t))HAA)_He(j1BbxIc4$7{m}y>Y zx-^E4kOb0wONGWv_9{ntFsUItO_DAe*c6RrU?gw2Qlm*#sFl{uv zG!#?HKvRt!idf$qfC3p3 zE8dzaVWumI((9FKZP#uoBzGbJj-Ze=VkH8r59?IVbe16y28JJHGB9jBrYbZDnKXoc zp(+&|4wwUwIRysGRLOLNG-zQqZKt!T9a9@%rCh5{PiLl(i3i|e{DI|SnS(@FDrzGF zoB@+Wrg?l+Aw<#~1(z!vDzI!btjJg; zoVjSCilWT`WU7$@Bcjh`crM5irB~);!jXV=(uG)pH-N3FR-6H(Fmq=)JV7MJ4+hNU zky&pHcA}Y$1ZuI)&uk=?1idm>ZKTiG=2*`5Vvc7PC=dxW!<^RHn~%9jB4tqbgZ#0u ztus{9oS39GG9+7`2`3+fD0HQnCL_orv{tw;S7)0va9Uut06J?9rOaYe#w2AH%EI00 zI&0C&VQ&kawR(FrhE#3IV2j3BQu$PdmBynpmNY&paoc6n8cR7Ywdt%iSc9)~P8z@o zlM;keR>vlKPc=xj3^p(^G93t-(h^KG8OJ+gk`9q@I8G>1!~qH{p-KjJ0ac%r31WjZ zxiXzH7RX{$a-jkiXLzJpv9SZ5o7agB!QM$7&E!aiq6_RIBY2Z_277kdLADmH~K0RB9S;%X;7;a1}v43s^aAk zrvlI^;Dib2DOE`%5El%rDB`B!oCXn+K$R{Voy#TJ*)U9yzga323l)l7d>m0g&6EOi zX6v-l*i?~3g3^qcdR?AEg9oI5eNU&C0t_!wJ-YAV4=!d}szJu{4v_-S<-0`{RDK`eg77GVMAUk*gB}utxj>eLd94~@Zr^?S)rmAyAqCogtqcj*4Mi5#k z)F9!I*vN(!szGfhr>$nvG&0-?Z62Ce1vEhEjS9UHcm!C^{U|*MQcy3H3Yw5m3MyYk z(I-MW#Yp9=fzXmrDiUiefaIuv?vW@Ux*CN^OXcSPeL;r@5}ghQU4Csja5zxpk`pMC z6Vo0Pzyt#Qk&&OT$N{EPrv(abEKuYMQ7lN0RapvEW|ksdsYZmJ6$26oJ#N~lGr_V2 z=31GG*?feENGb>9Ri)8^07VUHX&Pl(8vey`D1vS~O{0S=3>0A~0GOrI>FFdkD?Bok zp|}xLy3(Wpz+{6I6k0RrG$tdZFk<-(jzfQ9VvFVzFy~fh`ga}E1pFoiVB55P=oH+m?*uWGSl+ge{R>OJU5}8F6C_tzH_-2VSP#RV- z1G^Zi$f^;DApJ5h%>kT^mQKJHgu9D=QFq}Nh&KM!G6`BHMX$;PutFC2zd(`8RGC(w zNrPBZsscF5G&DPk6j1=aL`v&pG8pMoRk~bZ`5&5JSQFX|z&1cI^QyvS15sIe|0abo zo{Rl?@tEaBXoSj%MJSyVpe5(%D8WlZ*E(8LjyWx!>`1=ZAhhPwf+FtD5}8PdnnygC z!U)y)Y2dUc1?qwJaz6#C*)K<_)=LpZkq1FE{Ch8(Vz>xZ9;`KKG&x4#A)sD*6OI*$ zP=A1rM!b?NS4Iz2w#O<0w*t(hXamCBpL)8G^KQZ0|;{?m5DKoF_TUU(^Wcs8X7%D zbIdEr#R#?xWMf4^Xj&{qfY(zKy2(p|0|6vqeBq@*v2^>zAPJVFBE?oQfV<5kXbqAO zS%YH1yiVpqS7d56-5X9ily#U6z0HL_$I#od03wd63%ECP-PAvVESnqij80~PX61zLb)O$GvjVBQ#3roTc8 zX@D?+Y2-2wp(UWR6;_5SWVzM|`M*9IzjPqQXy61ayrm6ewmVK(eTgwige#*@ECg_P z?%3yqBC}W$l?HKWK==qFMX&2vJBJf{X9!>zElG&){GZ1vF+iTm1|g7&0xnA37w9P3 z(v|uQ*c$>Bof2aZTGIOhplL8dMKotpykqcbav>9!O6D#iCjmHEHU<4(M_5D@5Y8&7 zzHog(FgFpSC_Tptv_atGtrRUrlE&aQuvR!-Dvt#Knz5H`?Emvfg3wq6H+M$8No6GC zu#XrDk&s3t*z7SmwMDA{tHc0N^UkWk)D5Z!VFDp~pAk%xAXNFkg((0nP*Oo>9gGr6 zBO%#5TyTIrfFpn@@PF14aST^X`#7x7d)l`UIy;`P0NA7=$b2z;4U3Zl8ME4`NHrm` zzf|mJ%}K~jspuLIG%OOK4K|yEj<*sJ*koq|dkS!ficJU$jfGDa8yN+z<`fjAO|ik1niVA zeDHP(7IEBmN*8I!c!3dFHD}aTy(XtoMy4HQQip-8f=ZK-1!}82!t+=WKKwGpm~)%s zLh-g1hy8B8<0wUWLiTyqlnL0SAg15>E$mvTras_QU@(^&ef2=}5$$jGXPKIsxfr>nr@g*;e+k({E%Y~bV0 zGxzf5nT{0)z-6LY7n0k1v5;NDs{3qMN9fqu$SK^?In;TpbeusHi04^qNC2!MOBe?3 zc=ftG9zP-kAs7B~(Cz_>Pf!5gzN2eLLLo4olC@1(CsKqbHnByo?D1Mb41kNl zX8GfmnSyu)GYp=>5qpOhA}-5hH^89`*fqH?&9N1|E{uaQprpi9Wv&T?d7#$`f3%Hhy1uQY^4Yw5ExJT5VmFuutVk(L>S)Q9O|^Q(ck{YL~^J zD`h4M&hmD;Ew8>XjA`Z+q;-pAQ@~Xbrb2|*C)Rk4 zg|1=gfC%q^M7;?rq%-1*(4zzLlmPbr7!_#(<6|U+*g!^O9_j5OU3$m^8woQ==JqEZ zm}1UFJ=_#P9RKb~#2aut2%n|&wHw}0XxSirvxLPv#S(4f%RPL}Ct)c^U|~0&M!aW- zqD$DMSUKj%$VDLl7b37m28n=66%;{pZ5Y2H5B;i%C^?bhegG!m6pab;u1I;D0TUlI zwjjd;Odm}jtX4&)FF^yWe&?jfpm(g5U@#I5p~{kUQ15%Fk;ZxkAu_EcTA8#w%f|HD z$ce6a;F<_)Sb;{7jY97QCy=(9ArG#kbS9%h1$wEVI;f|GbrJxH0^P-0N$>!d67j_i zt4q90#qS%m3AfP%VTtrF$Vv*z?aupYDMCzhnAXcq4Yjjml4_Vij)0SyYtAKa8at=R zUk*wJ=64&EUKEr8hwdEwni1)2fa0e?B8$ug{XlfGmc^u@+huEkXXm6?I;*!T2NXE? zm(L>q{2Wa-l0D;xj`)_J)p_fCXCfD6o-1&K5#-p$B*NhfJzO&%V69U*2LtO)qXouP zLu9n%h8!MQgkp6d^2S9^2nRm+M}l?@Nki0}(U;_nRwO3J6>_Sxo+bbx3;aYxfk-^) zccLvJRFzK3B07!$87uNd@sUbeBJr;KBdiXxh2Z^*)iSM*ZrwVW305xaWDZR!eB9Pl zUW6A9J;DSnEe3km5fU*Bkp+?+mF_g2$XJm-twqeVN4O9S4w7P?16+V$6l^f)oR4G| zAcw?@gH;Yv;f)6DzN{2d4zU58as;0k_JLiFg=wTB^aj+-4v5A0IWF(1E-n=>3X+>! zV%9T|DBMZgi6RGyW|Cv8T87Gq@b(PLMS`?qN#`*igPtDXI2wmVSU6;kh35ziAA@)5 zSX~AgZWpCq3*?3_MOGtO{lEi|EC$?+Sy+i*_;S*4opiDANc+XC(?}ns2J_^zrWeV| z5Vt_{4x|fsOynsC-3FsjMba7I&`+h9L^gJQW}-|KyevYps{$DTClf?#pBxGh+?ZG! znds9!lLNhB68Y01=HZ8g$N|Xy@t(9hv0|q@%xeDwwE~tZwX|@0V8%0=B@dvP3J~fF}U)4E0=q>Sc?6m}4}3d~Ie35v|>PFBR}RPpy@*5>c8Lgo#uw`E{OK(A7Y_!8h- zu(nL`+rmtY4F5M5v=IQ#)=DMsp#{*cv#nVIDz|7PzVCl1eaKKOqao8yH|Y0YHfX0! z|Npp6ZnL5w<^mo#2n=S$e*kA|lp#PC1C)XNg0qjgWwjP*d7+1m?;i@OR#n z>cOTQ45w&Z!t@0uh`Ee1Yp?@uj>ofpx=Z4YRpZ?sY$-TUnfHXp+b0MG>1v z>1k~NGG`1}WFjmIz;Ddpw!ks>980s$=zTP1RFZV$={T9gPa_lS9CdK+wwbWzDVaw{2>fiVy`~%texk1P0oc2&^Q9y5FoET9pugc$6Ez)-JBB7z}qWrZ<@FPNJ=_D8hLH0R7 zc9TvxF}y4-u|--*wwt$7iHYY)tIYxgTRIN5Yvdst4_R!Nd#5W}3#{k~Ed*cfbfK`t zM+?S4p9m}}z?0K3Y(bHbe;yrK=u2v4n+6?pDY)#BpRfeOvGW~#F%1u81EQ> z&Qq9ArJn_%V*zF;%}h-Uu(jl-gvYz$#?bYJuYoeciv-*%e({H%pFxOy_QEgHAktSM z#hfubI(GJY61p!Y&V3|71s zFc?zk35-+$|7Q&h$=C3cA+X$tY`H4HiY%z4lD4D{-_ztKDXc9yFhD8__#M8I6QNgf zL~v#%nh5gDdmlCPh#B(Oc+*HvA3SO->}_08diu_w$LNNsFinUV(bZdED>~6*LnsRJ z5=@GrlWphOTTzBZ+f@Ouika7B_(7WGEqGzTWnmGzt-x5M#}>hgi8mi@adCkQl*k@v zKUN=$FkQj6)&fl=VJ)zxi&?1r!O)mf6kh86>}l`3x(K6XA#8k!P-mkWUdw?YY`a<> z_|%R~1oAjWE6W1(!o~a_qWgr4m=d6$@!8Aj__~)t z(L%uNU>AqS5Jg0K)P~)8DFXizXkpw~JPcB~LXYvym%X;wHhBMShleR-;DyrzHGgNs zAhAsf3Te*KcCCiZ8lk)yRpAf*R_&lWh3(RX^zB_q2*MM@8igX05o{{Sm>?mluMX%# zxLAtD4Etyv*k8mus8mLj!z4)vIf5x{s9d2=mv&Vu4SIa5X;6UH8CZ&f_hETp?1;7T zBI^|Xps8r040=(38Zt6Z#gXM*q%?p*%&(gAc|60E1-O)v$V9E^$7AwlteMzG~# zwFeY=bbP5hbMwS3Qq&u33m<68{=+5pu2XJihocqpXf)^iU4y2p%$^|%0)1$Z6e&!` zbVZQDr~^wB@2c_zH!nhk6f6h9O&XZ+!NLM$%7;BooLe$vX2@Fk85d+9Z%_>Z4F682 zD!|6CGE5228jFB_Ni6L1g^PcUIu#HV8G%CM2Q^CroI!|LF&56E;~I@`5?}|(4W=|* z3VQ>8anSOQcrgAWmBm0O;j{<;M~lx2&@j&c=^%T6E+RCL(k%cQYmO5`i?Fd`wR_fT ze@8&0LBQMue*j2ZsDq?%NXrm9K+hs*Rd^niE8e*IW(K3e!)fbq3NXyCq5K5gm_S~P zh!+#YiwWk%h=lwoeoZ1VKbJ2*ir-C8nBNI8zeO>> zdS5;yeEHS;@~ijdkI|1`m!FM-`~ms%`xU_N1X#r5qDTP0U?6`U1Nn6Y^6LuZcQuG# zJ->D_f7JY%YygYjDL)&z_&xCF=kn)cQXn77f&7k&`Ct(9N9fDPBwv1uzKA#`$;tfz zTThdY$BGe5Jc+Z%>Z4T9m(HSz{$%s*^{*a6>|YN^DvL7>~xL z?~xjG7&6V70k54{o4x%&NmLR$ss-t054l%qQv$@HconAnjup2aLai z2osoEfs+?xuXv;C<@2;iVScPLU#`aaB>5dy@6rWDwL{p8YAew`DQSUnoElOGmsY~ z1XIQdkRm08e+MY>1>;A!t>6q$ia?h`X2622c;&(NHY3Pb8Q^jZ)%S%*tR|89Xy$N_MThugU#v&6#W#-Y6Pg3&&4^DagHKnq?7V@B z_#jk9PlbIVz(fx+>#X+yT5SaJNwxtkCwLs|4XYDJu=2 zjR{t?s%1-`T#*mCz#t0;y&R*-wcz9QCL3tg$7z`y^FLDKS}Ko)ft;gh5pBfUv5ow3 zpb2kMu-Js)Rk+fIA5*Edrz*79|DQJDjHnoTKS_@4==E+$+ zt0VjNAE&nlV;Z@vqkC!XqswVuA31~It4g3q&B{{5lzIy}cnR1QAMb-49~ zn)xQDcsD(WB}exy8fC!;yGCHzqwf*Sk`LC+Am$v%9RTx`kUWqix3sLBZ~N}gUIm=@ zb2c6v+AGO@_(x7TjJsX-edk+`%KAAXs+a*5@17KS3NMBU<08LI#sJ~AN&~-e*f}cg z7=GL)@gQtFw*xld#0UY+QDHh0+!&>oDY%lp z)4opZ5^?*}Y|B>)LLsSvhKd&Sg0#s0u5AnV4r(qcg>z5^&%B4(CL!WEh|(@nrof`q zw_L?e2P*I1fr?`d04u!;mNi?XR*~X#yh6+alRXAO6+|i+u9E22*`*ZN*aFv| ziiE|-pt>vC2R2du?rr7UQJpSL}lA~VExigV~4>J97?@y1LB8gz^WjOJZ~ zM1k%YxVWa-AVtc1_xVDe={b@bqm6>=3!WvleVbz$&xVMNd9Zh`D#Y@Ky<){NQDe6* z+}%RV0@)Z6j^dtNXx6hRAaPW_5U@BZS{%?gtPdx?J$US#Yl;FHJ4Fitik(u$frq`S ziU|t)oD&ZkI4dI!L57v=mnBQ|?I*^5jfDW%e!(KZ7=w-(7!mW>Ca#5p#CEyjg2Q%g zg@D3#A;)0g%4L1|Z!i9bU$`LFugDJ*SfV=+U0Q19zPPFL)ac1@I?QAa|rZ-FXI&|q~3%T-WdgJMpdu)I@T;(xYo9f1K97_ z->VueP#5wV17wR%|3F1s{AZF5Cy*F)*9W$; zwFZqz1@A^8l=`eN9dj`NX>yikKFZ5HIHN@ZkszgwP-jzG16+a7-H4-<2Iw(ek|l9N z{-geT@Uj|Yztmwi5@d9PWm3q786qa<$8fF1d-nN}UWlUUmC}zSKiHx$H)w0#WN+bS z4E3JebTL)Z$WCs$ERi7Y#BvlSh9lc2nzl?L=l~Si9~m2du(p}o8P*n6?A?ZMg@x%L zOca+=@*m~H3qAaLhW!W@^)?zFgnqD@#*NXW54nj@D>ZOiOP&hSR79R>GJ-dFtyLtp zfR4xz+(Drm7I4j|iQOG|~tp5GY^ zGQ@A|ErUXjm@Ogf%>#$8@=^U} zH!}bIF3M`o7B#l^sbjsRVyl~G1AH|1&upp=w%@`XCce{2!p@UNObtJtA4UXcg6hme zX=YDydS=AWA325<@SQvH_5=GW+dc?RDV}FWGzr)NBTxtW^*WgiWE=%i2I6s++X zBdQe5AzezRm&(ip%c>FNi^-f~({ByVfK(yuI)X%vfes7y31z07_DXzo?~tgsFnidK zBtwTS1o(aWjKnib_%;F@OEUyaq1LV<&6*zA`=oW6EjN;=en6VI0%-)Z;g}d#p_Wq_ zT%|ItqXHJJ2rEFoCozU$5hLP7ti4fk^UKv4aM23KD>KHBnk`6V<+l)dJ}!%}^IH3q7QHven;(atR4B-+Umq}cgLEy;{zI+g#9T1F z7a5#wTmMd1pxB6`c{<2N3AR>AyqY>)fjV7*>hx*Erycu}g*gNiPQ!{J{r+z!-Fylq$k%RY~3|0%b!Fh zPsDgkB_GgL@Vm3@;3@^4C#sDKu)hd~=B3=p=6aLG&Tkw(iA7*QYnZ!fi1_s1mhEIe zjM@K%JxVl<@yc9v2G;)lU>69iCM~j)NVVQzgp^RV`Lfg)57(#cC`46Q`4ZBR?Ja`! zC<)osB-yzs>`IWx88>4&bz}AI$T+zK%-@0+6;dPQqaTh^X>=O>d^ z5j&+&ioH@$BU6o~S5UxVWUSH{%e(=?REx=N?thd_&T7&EENIR;3E!g=5&Q?k0=hX{ zn+@zO|6?w=(Mo~&z~)k!jfu6X6;D0Jo=_V#2GCJasJT!hw3nmP!+R=DJkkfSJYK{& zZ0Q=x3)2k3D<%%TETc6ELREcDYCT-p5j()L4+Rlo~ESF-G7P5jyBKRl2;+`S-#yM_%(3Lkl9^0+3Jw}CX~@w%h94;vt4w9KSI7v~*85N@de4S% zXKfBAMh<#?6gVwHJ`reaM*B5v^qJ9Mp&T3JhudUkKv>ZQ8|P~RuAWKB5aWOITQ3XLWc)qrEP;|7C{w;jc>gy*;r$i<;r5x z)6>;*ESvPjuU{+~xe7WsH_1v~#6VV_BSBm1r;w4o^BOGtX_3RFf)fjQZ^e7R<*>%W zJeb?0GKD~iH%QzA>z7xBRAHf2XvOn}R7h#Zub_}n>g}s61oYhfnZIA!a+$>6#cjDv z0!cvOJ~|LF0rI1QD`6laA8dzYHEB82OTamXfl324Ez6a6c!5eou{Dty8gFqe!jL0E z8OergNhPt243-;jc@Az#vD9a0+rU)BlAqqDi%bS>7cUZxuwB&FR*1v_8g)h{9Qt)R z%!sfq0QgbFL=$6XgwB%7GAHRo!3L96OKg!Sq3s@Wc2b&&ury7!9)CG@bdsu6Wg#5U zb3D(#!->Ea&9>cB9ueXZ5!>ZR3x&{F8wAaEZH3S=+l3sHFD|9AWhO5GD28QHuq->4 z?|}x93~L|4A4W&f(xxpbkX>y<)Lpqc+XS94C`QkgCJH%}GK>A{ftHpd8&%-hDvPE< zbS&{+gw=FuN<$P*Njxo0z$*)LEfKmz3hD<3O0?S}ngJxrIkY!TQW0=+$!fjPq|`vm zur^eBb&f?;1F7-?aKx0&=nwrTs*wmv&=L$U-9Q?mW58Dzu%=*&oh7$NNs@e{Ua2xh zsx?$7Xue_HCTX# zV+aMYFKo8Id34nU@vL_!v?E;X-W1-X#DgDesih4y?F*FFszo40!?U``VK9=)P=i$` z*rmv$G_!N-_ty#R;~IGZM*X0hm1xsGl0|$2Ibo4YBf2+MyVA!|ThhRx(6aF9ev#FW z4k`4)r{fdA6)_D?n*qe&FQ+|ZHahz3VK>nZ-vklJdtEvym0H?&=PT49$-#|JXC z8kh%!El7hMS*}MEg2c#`xs)ZwJf?Tp*9qSLCkkO4=EJ^g=eL**KcEHZAFOsecC5t; zc@WDwF(MwZsUlnis05_JpALMyLk3J;SQsM`B9F!3dQP34BPDvR^n8VfDUicpHf6%M zlQx90_D64%<{?tbshLn$2SZnbzhg{pSuW!PV93aivcn;Rr({$)YsgG**<=`vjMF7N zSVzDFYLD{Rs2NQl-@!MJ?7nw6ysKeqv!8FNLM~;iYas{hMlhub=KJBAM@1>%nuF3K z=ZTcwD8=UBX{dth!Zef(d}k9g*SSdw*uiW7sVLwV`zsU_xWtC*D}_m`2A7kHEUG}E z)MwxwxKkq9bIFQf?)VfUD1-Z|hAtu{QM6avuvkw|UlB~!7p14~40=2cNg~hT^xI&o z2-FQ=%mxNngiFazj7ci)1o-3X(9#f#Xt07n6OoIe0+%)Oh!EqM(PK@MV&ct5TU=b= z0wuBs+K<)8B1~7Xt+hZCNmvW4>0&UCKbQ}`r@iy)!Ww0;x){R7e>!V9KBC9z+~Y9c zUVyFZEE^Y9Hlp~do3=en16#-U%*^(Z`yL&=B94qcbb5c7$NB6QZ5`NUB79B;`BEyl zxdI$yGa@VnK{KC-w^zh(kOLY%IPAwev9u4t5^cOSp!SvA$PS$bC z3@x|?Qza|)YL+HQ1eKAbH^E~d_=Cy9jLIB=Q&BbxYft>}a>Jp90xh{nBE#kT4-dpy z!owu8TzD)?w*;4BjFVw}cId3t!0Exd30;;c$D9d}!d?R+f7%H<^S(&}J`BxB#L&D# z@W=sM2#(c?NJSk^WDywRK+8#h#T5GiQyhp;(m@}QmlHcoaUlaQe1lQ*SuG3_>%HZj z4|PSHC`SyW8rVlf6wvCYi+k;@u( z^TbW0v~UU93NeH`wDJ^>bs8FX%yDF6iJvs-d4GP#HM1czM zB%G(zr?FVUP{2EXxIh5U@On`I%7}PHy$O`2pcX0Aj6uxsj`}Um}gn?16s5~9*yRl&&RNLaV{6b z=RCwV?h3J8kR-W10*Wv#DcNDF)KO||ksZn-`#o^#!yc_a3{%2x5i=!VbO)O~QkabC ziXeqirw|1s#=Mh=T>{EvLWLAq8WH>#ksn|v;1_lc#}_3$^W_X|@UvmteL{?rNTdQ^ zvCLw_EwcF{)N}xIlBZJ@pi80*Lx=bxEc+zZs`m{-;-plVE!vZ_B7-s-Kqx?b>al1A z65P=1TmlC}@=!pUE``%RpD58n?|6B*LMn@aPJ-MA{*O@6YKCBa!4w7Ao1r2?gPtL9 zpbaymqGt$xt@d?}mTnQNHUkSp+RkcjYIwmHGcu?-^+_-cM1feb`a%GN4J7sSAoDIRv@Sde|lCF zxS*8s0?3Qvy#%fv0um>f1_{04gLpw3f!mB#Ra^vR;cw<2#r(nhbs21lDvKMyD)WL^ zS+rk#q$F4zAy~M$W!KX`m1>^!nP}be(v8;rR3o~!rI6*XH&^~Rd)AbmhAoYR-=c*zi8PrymHgUZz}o@@eX*IJgrl& zsSP3u4s09q{fO#KQd))Fo}ak&af6NW-lxtU5=M8F`ea{kUE;xo$fc_T6RzDWy)3n7 zZm9d4TNgiB+~!*E?KKyStbTdYC#t6x&M!UoEb-;*WqsopOZ5lVlsbRw_s`B5LX5tV zCmwt6pWos^PP?qZzphzRw(2hox3I z>e{X{>7|5QWc6fw8oxH|QGVNEozi#Y<_cHJt=PD1K<(g&%aWOG7EYMydrhZ{NFUd_ z|Cw_0+)Moa#Z14wD=salr`l6Z-s;$|nTv+$ZiLh-`Nua)OrOk}bFYDMX1zvV=Ra@W zu++4p=z_0y8;_L_)glmMy&?pULWm0GGpOCJ-bi% zS=%~w@~?T1WWwZ%wY!!pH)h8AR&y5Y^X(t{z$NoW%VpI~FAi%D{`pKf!c;zfYv*t3 zf74&EvSs(B%|l*K-}@#!ez$$JaM#j%=(h}vDHpH#3A{a%LDL=k%{lI4Gikhy&OG^HH zRwJd$gL!vmUJTp*WS{HoJ0;3|y0mSF)fsmyZs>RJ+f`#LcY9u|%Za$HUp#K4Iui8r z=dOzmO&a4p_0AVpK95*{LE>G)h9o235jHllWIJG0-LC8042mD!O zQAWpaMy$^}u&nvzC(689s?f_J2uUgJ2`>e<9YNw-rJ}Hsq zw3VHhxc{4p_YQsbN9XmAA1;~RYW(ad8RiO zN>eKK$ez~n%ihi7zY}(TadxN6rD?i|AHGkGA6MyVyQ9DCuD5#Y^O?6cMXTB#Un86v zIXP;0xc|e`r3dE^2%TOgbjzCM-^TvBD|q{?otN}=)`YFODXexOd+@W9F{eJC8C0?N zmvx#{>-39X{4C|4*=~|HwQq+;U0=W8!pw0`zG<~w_@w!ZHOW55hmGpip-(&YP1pNw z;kRzI(%uPM+R#vcvhVh84gVNGR$9X9eftUOM>C(@S6V8MM5Mm+`^T zJvCbugnl-z#k^O4Kdtk_r`cNhFV|C-4_daSt8V{|^quafj~>l(P3Y?JX27}u{f7U( zZA|p2RtuLd8r8HQbaK5XXLe5>KQZgR%k8lVSqq=tP2bl0#i9Oly1h8my@O!g=_B>8 zHYg*lb9i=}yY+oduYN7p@!5sR*|QcNE4MVGZ|v5j1%CZ6U2PkDeYomp!_WSoe7+>% zpWWx&SFDkYzAK1*L|q9`#*FxKoaT;Lu*)O$7}{rM^JR}KHxIbO4BeuwNq7Y^K;<*Bb58&bsEm1zS5;)}_wa*ucB`y!(4L{y4&Ydc^i_1AhJ^^rzc1 z_C=OZU7cOfeAxL*DSK5}BU9!`4>#Mf;(q0}BlrFCqRjB|$HsZ?OFGib#kg$lt^DnZ ze$C?i4;@{2IAf|$_7&ff_d33;bz@qOh_CPdb-m%LYg?xqyC0ajX~dn)=_%7s)*d)v z>EMHP*YDZcFK0!{`a`0~z%x@?$Ll`r*6e!YAF6w5W(;sWx?tw@=7Zvs-WYn1ocXxT zCjg%00Y!>Q?}KB~dR{)5@UrX|L*`GsezW`8?xPLQC;5c_wdG;E zh4Z4GG*Lut5(^^o-Rmvg_37azHCq3?u(6k^S5~d$D*Id}mq}V>45*nOS7QH(1>*eYfF`H!Tw(A>AIySrX z5&y^uzDr{6#hh;WY@SZ|?Tg{-eZ(y?;;(2!vg`d-dD1sgqq35!KX26U_O1qXUFEWn>E}Jy`^NZwxA~~sj6xDzH|Bhf~FJfIsM(1 z*nj`Jd3S7dR=eT1c5S-(U5(Z1>zz;fl{wU~PF%Y^Z&v$7{X5l5-mr(qrB{jCjx}Gc z+Hm%Ea)@`Ddfkuf+U~vDGrsS()sMGb8nkz;|59Do7t3!av_14ZXZYx_LGFG1XSDxn z*Y1b;OMZH^AfbAfVOe!=z5M1$KkDG|17VLldv?zpe&Si*@!xMbQ@TgZyqx3<5$A&% zwV3MdelO2!>$D2~{@Y#+5hn&LJKjw;b$YTV|6Y5GjcKd#1^V1uqABkxo`QrKX^@mR!zvVqDWzLWz4N_93 zFInliJlSi?)V>1-HEOS1_A+5s$`^GWpZlWOB-5JAt0mTdzcS?W#}SPNYdpXHNiySy zAZhZ9pL1g>WeHx-37#C$!o73Ui86PEfA}o>yM0IZ(Z3HIcx%}9;64!J1duZCY0sEe2oziz2Ug_KJGY&@XJTIvg=Wm#)P8xG3MET;U z(?ehG8kO~^RnvtHC-!Kz(D&Cx1HKV7j@ehb=dfeCqoG}g4Zm>h+$Ze@Q&n#b`Ke$; zt239hhi0_CT>eJYUDv;_?74q(smAl?zG(LQtMa>QOX^jc^I}cq?I-#)=<;L7mOn0d z)?h)uS^?)nI^Wy4>dn==<#PS^j(1m!%6{8>+MIr`E|s16soyJuPyfrO+BY*^xqJWD znMV$G{ITsS^R<+}1m4s`f4yT;o3e~*gVak^B=Yj2XLHLv>Dt+Q%(d?j_0F^5kbsWkLpe1!+e#v^A-#-!)ZTe@uFm1D7Ac01_m<|1&JKV*S$ z$b4a4n4-Gn-K)7*=~Dg9yx-0bm^QcKrGK}7*}B!ktJRZ)6;N_z7ne8g9zr+x5!Oc$ zjofPps|~Kw@`yTWa&D>DkF&n=4q5OlDsE88UP5n_p}u=l;itkza~jO4Kca4?(U{Z5 z$48~tcq5UK6*eSZ-^3>NBJwD7Tf`;M+hr=vbb$`kbSVH5|A6F(nSy!Y|NT_ ze*gF516zz;Teoz?)+wz9ZSA&cnev|!6TTL2KCz?iE?ID&2;;ol-RtN4x#U8OrcR^2 ztrbW2P1=5U=I9)1=y%nw)~Z;2RO>~*yegaDRa&;$Am6)!ezn)-F59sF$Amu?)&A~4 z&8eNrBxm^S?yzC)-Y?qR&&xLM^=|ap-5Ec)>3To@A$p>zJo2lJ~aqXdziy=4{Mj*9v~iM*gJi zJSyT~Q$vZnL;s9_k^^+$N8wPn`GgL*xUym7@!<%7FhJ-h_7{u%guVel0DS#{00h&) z4?=_rTj|#(E-qDn;<iD40Mblm!J(T`!##HTAckSe7Prse@n{3OjuCk2rCD(a9JG`uwmo8^R zM;GDPjp4sl_^$nIT)kjVIfcJC|B* z>HNN5N69QETQW9E(t;$6}?@X#R4;SH(hr$+~C0lyBczBd>b*WYlQ3eB$hP=Ey7HPmlLZ$Q( z4%uVQ>?$0xq1KSK@KiyKlmWeTS}$X!+Tf)!?^={sYJrzhTi}(W)EnV1g8|HZ8oZP$ z6_sNoWzwMxg+8qpY6JESvC~Vrg^~~Vj9?mhnqw%UAh+-M{i}- zP>v4DqQ)SnxqZm(m4n_NsG)mMCp?b;Q|Jb7&eFu>t4F}}*w*0_~*WpF}o2&yRZhs#9 z#TdEQ@u0n{cg#pAo%N>Wzugvklp0VyB)L*Oc~)-dZx?UP_jw`j(>-mc$~W&>n-Z;(Z~b1OLHXae7-}Z0KN~P;*O#5o zE}Xtu9QMzdlYM6moSV3@_O?l3jX!DeQ-!)4;=b*rIuJ9sx@^hllfPg4_eiM{fvZfW z2Ew5pfRXO0G#gVXZQ~ysF8MrVg9@=RACZMX+)bb`NE9p-`Um(2BJM^k3=#|Jpm4}c zQ7vH&&(fv7ZZc}p!&Yf7E@eww1UsS-VFy?U?rvoRtymw#LD3vm8?RVpHdx@%d%<&3 zu-K)_^lE0QpgF^{m9eU}rm#AywshHw+`?82A1ph^4A9Zp6;$dClQ*eupVj_7ukMgh z;qsO9Gw)Q}x@*Ix>&8Fibvm{lt6e*P|1Y|ulTWXhwQ7Hfr4vRkC^$B7OXzP8Ry{30 ze&WN=C$w3gvFzHLhnRZGOH}_m$*Llx8o9x%u2<$tqa=A6eW;0wKPCn3X zYM)uXwk5ypm#ey5#^ukut6a}l8NJSb#0GWjxhnC?y!IcNGQ~aV)qocJMi_H%UR&6_ z{ki0hxjqwK?d`bk+>&4J9?kgXLG&c8@4g?`y8P6%WZ1#R!=#d#&HOTZo%zMkuOK^| zA&Zv*QWs#VXp-dO;*Mt6n+XeDMl__E7oEzG!y-{A*gB2MRi_C>EEej*&)4QY@)S|W zdv@8`G^vVW)>I~W5{@%%D{L0@wv-@z+lU$#Ki8obgea>$PuNp4cbn=tlHy8Dt zvMX_Fxfc~PfBht@<-|^-p46PXM9?&>{9jiVR9s^0+WMb{a@`ogsjR)~Z~8~C2u#Tv zy6C4SscVnj2n~ro`E#|@tMgNiJi4}i&hnNgR_KB}Z}j;@w=lC@?G0-$hnSl7c-Sd0 zEAeF9^43pZl@blDvRpW{%3@c9T*E&im31x2ru?jv@0_8op8|Dd&a|c6L}ko@5-!3z z=0GVAQ3XtzeT9C&d;0qcQ-nU2RCiHBcdxFKzPqzz_ul4N^~Y@5-(~B{)4kh;k9~6O z2e+-u!(4ktM+m#q1ypIJTt)G)oIP5WcXO@fUZq-%^`l2D*uP-W@qDE)=jFp+*L^!t z*qU`lclVlcVD+aj zynXtfNbgVm2T%Sac)+ylgO06SI7mC(Fx~xL`)c>A%)D6fR8^P8`%1*DyWb)9s~v50 z>yLJ5_uG_5rSg6sK465*d;Q!NC+@6ToVi+jIP3FMxBsa5MQE=}p9Rz%UM2S5^UY^3 zc-T5SHY;V)jEOE?Pd=C({Ibe{6U(o+dHF)R*(0y?@S&mu64&(V<4+x`RHvCX#jA0^ zIp0BFt-37TI^?{#<&qt5MtJP%-z|6G;0;Sp?NC+Uw&?Dif3_a%*{O$n-L%R5$GNoM zT((`cft!9!ZxgV|APlT~aB!3^YVYHX3$}&lmDrv)VfE=(BkorUEAzMKk7u84>oa#~ z#ovTOD<1YNLra88Rdg*c8d`A+L~bxI4Ujqwt+)`P=DWJU>H=vIL3-f2`msv7xX;OQ zR|_+MRCs!{aC7(Yg#FH1O6BgQkKU2Cz-5lA`iTRsV~-B6+M?a=+}b@(?rqsg_+#BR zck^6Jru%L^w`$IhJ8M(`iIG^yTC8y7cX2IQ;n(0vE&moym@~B85#SA7;b?o4<_&dU z&HiNXqX`2!Gc6n-LK`*av6>>bit<7a^nvfr&iMcmCSVU?9AdGb*cT4HzJxvW69(d- zI7JvLsw=EbdRN8LFXTP}WMFZjB8I&yU3?+dfwj$LzQGTrOExEep})JoN%bp!wY=N9 zli7nGH2rLLCC@E8Rz~>UIHZrdc=g=g)#VJ|Uyqygyw{7ZM?z|KRID$()A%|?c3|}y z<3Hl$Qva+omaE(#e$m}E>oj6Xbj87b%7;BVRQfb0`|E#p2h{dBRpr|uk$qB^E!;9E zYG20W-%mF3P<9%<>brf_x10@GpCp)|>%74*r`EFvEqC9pHL3DnW!BG3`Pz8Z%lGWP z$}eVY@7etCCY@q#?{C=dtFgP9)EpgLW0AWqt4V(P996wZ{hww~(X*7nYZ)GH7m(O( z4wx*zUp|fh_^?dRB1brrHl?Mq)^DRa=9k(R*UEG0sBTk^Sj!=Rp|h4=;}ddP`%Tw^ z26oHsTI0rIzXJzG)#~;9nIOEvCkel`zZ2dn==GR$$_-`ilx}ycE3&$k5kCt^iBQLf7$cuxodw2fC@LjK&4=4Cf{>A^{ zHP=Y>i(1O+9($gb`d)k^a7%~37>`pkIa zYKaZ4^k1u{oV{52t5+NSlf!~^)9>6%mBtQ}w(y$i@!i-z+vk_6d9BORh9x}ubu^5f zx=6KZ#UD4bdN#jzHTBV;{R7{$_}lbdT58<#nl&q42tRpb*SF`djUOK9@o2}|CmW8R zRkzuxRqv&yeINYL8&1b1K+u1Wrh=cxc2UiKbbliUR3AjfMg;wSLVqOg_wyryeoOEp zQ{uvoy2tZs%zZY!Vn&Z+-m^B1Z@sCJ}*6bQ;mNOAwJvoo{{Zqdf@dYznnSc zD!1EKGJeJ+U2x#9{t)$o#rt;^3w1Ad#M`r_E($# ziE^Fyll!B}jXmG~spoIH5ue7E+FkoV`TUVz?P|DbOM}WY58WL->q7tTZ|2`PI)BK( z*Ke+mm0oLG`bEVBdfy*g?d_DJFC8p1UTCH*Pz+qSsLF52Ym+rU+_=AY#fzI><7)f_ z_ev$>Ml}g5==HSsRY}*m|9mFx^>wGX&G$|i*8lF_|7zmw!}DwQT$VLWGwaH2W9x_x zmy{h!NCx_unoJ9sX_|FFcqe8@-grVLxw3wnMDgRw`b*h6t_2)>aFj{EwUY0RFU-#$4! z_I#f{Z7$qO`ut9ntVgFhOgfO=FG=w*d|bsNxjkkI%GQlP)b5v;*Prd~px?OZ;@^Ht zs?J%_BV$q7Wi#thYp+%ihWXuCaopwj!V6&r(}2&yhtKF;@%)OW$FedG`bu;Mr`4M? zV^CbBNte}cZpTO-#UE-|zRT%`CH`!8;EvQF*!^M!cG0r9-(%i}!f*Sxm&aNC$aF8y47 z&B|#$%SKKE8QvUN4I)TS-(@(|34+`7Y%jo2%Jn?ENvS3ak&N8lIG*2<-j{< z$XH=5^T8NoP35c(z=cSg8d*xZi{KW0=*r1I+~_(x_OFbh1{jkUC8oj6XXo z?dYIpPjiH6(G3p-mg;BN+c)LlkT2c8`E+!Jqg%R^tegHkXWzgfPy2g#{;}#xr7L0j zq5X4)`B$6TDk-^n-_~mH&I9VD%q~^&^r4}*z8b&jWYUEPvo7vDKBGyk1^I)v&9AcJ z?wJ;?E|>p%>Z2*9TAUkncM89VTwEAub~YroDgtAzzG2-1e_3XLcj?DCj^`ja6-Td0Vf2U z5O6}k2>~YroDgtAzzG2-1e_3XLcj?DCj^`ja6-Td0Vf2U5O6}k2>~YroDgtAzzG2- z1e_3XLcj?DCj^`ja6-Td0Vf3hXCd(0%R8^Z;y<#hkB#MW$4PIf`3f>{wEd5P3C#e<;kZuOwX`% zX4ePaXa=Kpn1A3pN2OBG4wQ__RBnCCz9#kUq{Ojbkz>@;^T3ovzofjE87W+?`h~h1!^*BuAY)jT2r{phu$L>Ts4*Rd z!j8s?;Fg`O(=s)1>x-uATSU+fXJgmLipFUQMXJF02!~+qo(bP?_^SS^#evv^u`qv1&z@YB}3P7HC^lRte znZ|B{@ix+s11{7~$Je7u-~6X-vlZKyy(yh=_mCLkyx>El$E~`Q#eb7I_{p^e#G>`i z{6qUhCVZ$a3|VyupyW3KA9;ZR4AuI?s#En!eSuFTB3TG52A^=9o{H3&z%(v0gv$b0 zGO=1`@CoJQfx1yUUD@s6Ub#4GCn1N@M#b8$pQO?C=2+Dm1R;m@vTUu&DSa+j~YroDgtAzzG2-1e_3XLcj?DCj^`ja6-Td0Vf2U5O6}k z2>~YroDgtAzzG2-1e_3XLcj?DCj^`ja6-Td0Vf2U5O6}k2>~YroDgtAzzG2-1e_3X zLcj?DCj^`ja6-Td0Vf3hS0V5?Vf*4&{aqHn3KvX#7f)!r1oXe;;#Y326JJ7m(J^70qdf(F zkK8<$Ja+R~^2E)3$x}DCCC^}N&)r;>ynueW2tu}b!FSoswRI@`_Qrp^wH^Y$bMW8p zt#`ujrIvzi|3IC}mSLMOxd|o?Xb$6d3ke?SM#d6-pj=nf_b~Xq1n_eK*a=)Zo&uvI zewQjk8*YMam#T+sgYdRXwV^&&_^ltZZ72F|1Z|<;rXkw~qu-X$5BNp!uk0d-0UIw> zeBp2OtB7&kTv9OjlgyT`o58{X4x=>GCk6EBl3V2^ulh#=ETRA=kpLSBz$jwzzq;_n z0JDh*&W~W+D8HP}|Gi8w8SG$8e${`+;tTNiA^5kdE@4C^l29tsLvH(>$dpS z9>5KNLuMy{EsPE3(jU*+&T=)tVng4#u7ac|kiMuz=!?hjd%#7oZb%CPGanjefE#`& z9hKX?ysSM555Wudt2N{s)QOC9WDD2Lulk2W`(ZGi(8bUnt1&dB$6$ayA9?d; zDynnQ7U+wMAWJC_BzZx-zrA@=ox!gIo2}Ch&}r7V4|w4o^5Urn15XQHBY3c3aT&p~ zkzitdfS=dCauregmm&NQltpm^H!_mVt=Tua{C3H{5g7xJQ1 zgOJS~Jp`glZX;))IYsbb#>^fsyRI~-3(d7Z{61G~1=v{6(G$RLGS4ncPC%aeA%fMZ zZi1x8(5L!61P|sx+s0mk;HOYWl8azH*oCPwGE6YB`ket^UvjIyBmv4iMg4aTU1OXl zSPc01;*wjnC70c*F1g}XWyuss|D%sz5WzRg{5)6e#p@r%SBE?yu-*lALh$-V`1K0r z7YwIN9t`m%y+Sqv&WJ9Rm|g2t|6RD8z*Vpg!Eoe{<+_dp+$mLgaAN6Dz-<@7EubAq zWy%fSoYkPz%q)l-1aXTXuB1!Ii@#sLS&!g`=DDPx^kH@Q^keFBKRmqQf8yb&)At{i z{Jhl6lI0Fex*?l&Od7uVp}O2YNW1i~zDucF0^#f#s2uKV4bs;)djv4gKnwc=-v58x zy?cC=)wTcs%uGU_NdSc;BwREXyd%MN)4uhXl;Sda>p$$%fV^sB!P`m+nc0=#Q zE=*UrFo7ELRfeks4V{x5U;ucQA1U(i4NzJ0jw#$=wiKeBFWbNY1Ph*u}! zV@y)t;%yHf_OSZPgahSUCp28<@%Q%OWj7}CxXPU2!f+2Tyx$89!h>+^;i0P7;6eR( zw8>6}h5RshP~RRNlz${RvRpW>1CFL%;OK^nlS18avHMiR8=^ziDTm`i`A5UW4$6oh zz6uOK?gfU!a53U=T)dqO3;C(IQ2vo{(dxo67&vZo;YgJ^R=`>#nPHz!{|j z0%tR@IdC$Es{FulPAFc|3%pBQcw^8|<(i$jWMrTRuXr{>IS+q5tyAB3;o1OPr}P5X zA^eT%9e>|+;c@Uc=E(TFma-oHX7K-5@OPODXB}`JIB4d7DxD9*-?_cx?;ICi2Y;07 z4S#1*?nwA6apAfHxZdpru0!~n&^!M6yYM*pJO9Y|%c87@Kb!x@g1;|LG4u87!1+us za2|%gNxkE5EA7QtUmW~Vt~dO(QSM0i`;!Y-DRBKja4nVooQ7_gj*i#|{UL+(2;KRv zAo{V3|R5c149~lLorAB-zDvHH-9SsS7rI*t+W?RpA?^BS!;);`{Q<6q@pUz zYN|Re)FfSE$c?3|>~w2D)p1tS%;S8WGZR+SsWbS3rc%;_gVUO%&$Tn2#HI9~ZNLqgQMRM5nD!i+=sp^ysB8_K9BdbVhW_Q+70#aP`H!P`rb-)aJpvra+r=Xml~O zx(J$Gh(3Qo6dE4V9RyFSt7ra=dc0$oBmG^nG`Y=poi?)@e@2+B^F9eJ!|s}%gI>1p zB&)X0Z_O)$hR%MY*g_BQ(u1vOnctJ1rhW>iXMRKfz5HuWv2v2z77UifnuE?4?qkK* zx-fX~1pCS%QF%zfdIYi!DOVUgl$;!jN|y!x>ACk= zo%UE?yp(!-P6IY*^QUS3W(@Y_Z=8^ryrMe8stF!kxFwitt=+?#Tbh`(VxrIPu+Lt$ zGH8AANTzk*k-9*zBm3+JR_<8yL~T|U(voRllfBW%iLIcaPo>Bq|LqJ(Otz0GgnPXvue~vLxwf| zDZj5~YUiRYGogDawA!)TdZDqgZP!dIv!m$j>Xm}w8Of@#p?D7c4Whpt!!L>k>2r1Q zY!Lr}T#3o^N=23H83?XKoTYx*_8_3EWCAzLm7i zpC=xBfzW2}CL6?J#$g|?eVEzHsXa%=r0nUu@|Da@wW~Tl>`^)Sp}6)gb?nh2jB)Wm zv)4;NN3F$G+E@8QQEwmN6P;(VM+D~H_EnwK6}(e`^QXY8zAg4q1wm^*`0?OXtp?LYMd+u2w z-fTyvh8eTuT9=;JwcaHr`!;pX^ue=!co#d^U1``dd^KKQWog*GSflo#BkiF*@l%!M z&&s>?#A$-TqQ8XSp7$)YZoenALVbk?TJhVF=T8EI)jDQ*JMwWN>9??_?}`6r_JXg< zZuq(Y_$CAAB<2?Og~{FRWmmd*`x$sk>j`f~UmkA*|6RP%*O$ec`sxX9I~h-JcpK0Q z-m!)iAC_S6yZwtjfe^6pL2yX44``R$jKmE6mspDOV7*>_%r zFAtwbOVX@04gHP0&o4rk3D_NN=yRUlCmVv+&_DBef;>mZ8`Ss&ZN^+3Z%2xb2Mt^u zFE2^Q8`SvmRP-in)@mc>=ykdC>M5I#zE^_Yr+$406ViDdee2*|-N*OYciwdDlzEB7 znlp;g0Z*A6UFQ#Ww9!U`KNK(U<#b4IYXF`CUv`Jqq6XFv*`u}YtKGG%6%&2A9gDw6 zO#dfqhU!NSB&M$>eI)CubU5jzTfy7;jIqI=y*!4FAYJf%%I{|kJ=uJnHEe*vVdi}y z(2TAD4(W5?vg1wqB`1X9H(+nB^JQZ~#r|AmHC>V(ileu!*%8QUoQExSVlvq^H7h?l*6%hIVc?fGRZGfA65S{7;A2i@}g11lH#b2?_7Q@gU5by2#e(nHTjR+jQ#^@^Tfyz+5( zuBdG6)Vd*cz-ATIU1Qx{FwMh(#-H53<&RWcL_P5$Z<*I>?@{!(Oy_Lu$-idK5dJPD zU-;JliyfTiGzJL0^MSH$L1%B7Nt)_cy`MS5#@=sR7H5p+oIvYw>RP;)wRfva%l6q; z%@F#}W;_evZ6A9T-U-i<3_)Laa4WkbdUtL6aiRD&N2Z9^1~pzz+HT?rcnuj;GmChU zBM(ITE_vXstv%D<@YG}Qz@BKkr;2gxXWo2@47lBI#d#n-=N3Zk!4+3I@k~!VvhS+b&{;cKkuqDj_xD`NQcb<(T*vj=wNPZfEdj=S%w^^Pp`XqgY5)c?cON#+Uh z!lJvaXr*n%CqqLUn&`|%tci$DOci-il`@T2@CauWm?5n6V-wM?l|F8#`PjXS#lCbV)E2 z&jQ9p$TQ8yEa-E?LuKQBOCSBfcNQ}9P@2ygJ)+VYFCCJ()3Kd)*<+2L>$ApJB9qkL z2-=#7OvCm!y*&_QD`n+)X?%ER`Uu*)gfge4Tk(0|Wlj)z4-DmQ=)uy#Sy|@Qr*%&8 zS@99%l~bljZ85h;kT#dPQ`|Zw;9G5EI(-K_c2L)M^@z^WG%H@DGK|-;M}UI@;0*$U zV9ErBskEcMGpVnB6bimYtSN$F3NVz=-$44_!Fbfp6xwjwp`6B(N&YdlLw`Z~5S~)` zRP)BurwbnRMa!VI_Q+N2hqX`E9*s|POt0>fv)tOba7z)i*4n_HZ?nxFH0rlkg-@}f z)r513eNiL7&DopBzi+c&Pv))mcl$bah>74YhCC^F$m%SC&)WJYob&}R9dJUe&;9AI zz11y`EeO7f7gm{a%J=v;ZHkrCvz+KUBav*1yk=xy(d$8{kKzH5ioSz6Ct{B7D7R{5 z`xFV6 ze==vPSl?|Q=iqH-Tt)3B^pA;D{GKvSzU;CCt){R))a$(Wc%iL7_DSSJ6=j*PPFN1l z=D+x+a;s)9dY5)y4M$c6@C=_hSnY5UtJi-Mk@Z>g)x|J zU9NH^Epzs(t|{9FO)r@pY{ISf%jzK4TB%@<3aEv8`)~c9t0;3PzO7! zW6KWagyIjdz7X$N%^V1Vrw3?Daq#QR0}EV5o-ys}+uruiN=b5 zaj|nwv^f=T8b^QVnLHOFt%lYuZm7AC80|@cklu8FBfXKH{ZGv@C^|bI<9bWhu0ri_e8e z%Tj1L7rUL}g)ZOwpk?6`rfqLNz5!2*Ug7^V>Cm%Q_QqtGJU+kS2zHk9$78gV+YQU|P5vjNdKGJ%Si>zO9B66T2y>!bED{ehzU>*j{ z%xzcB=Q?{%Bj;V&jtx_?-Q($I;o(tJS9WT224{XpYE9Z%#0@`pUmGPeQgI_*xfVE+ zdAaZfGlohx6fe(k`Q*#+GJN@^<$AOSULHx`sd7EM*6?!Kvt7J=rVHb-^729Y^7yD{ zx!y(J&{DIOw=6RKy-^&g7)*a{)duHJ!|V0XuuG;JIvSa7=vd;?(UapXt{iXvfoTI? z?op06-)HiVCdaQi0)Mw3g}*O34DV*o6TaJw*Y|xBE;$*y#UQhn(;8RugT6ET=#$dT zC0{*!hVbh=e7o7jwc zYxBTOzvTSJhfU9q%{jmx6TA3b>73d6j_5<6GsItIh2r%tZdU&v)Bo1fBNgAEf9rVG z|BKA|{*Z5_mF8cUUOMP3%ke*M+aJ8n3Iz@nOt6}AzmXQrzB@fyaCe_5Hjdix0;}on ziRcA48UAk%40UWMZG;E!x)As-0M5z4I|;bUICuJu*~2FJK6|o%{J$ZKPCsl;aP~dN z;CS&&mu_c8D)JcPi|DIWV~qYJA4qrKa)@S=j^}o@6+xm`?E$!F2ZJy0JF>U6s zwm#|)H8tEhbYMY|Z~kKTw!-E67aCovdJuXzcwC0g!~b}&FfF=_b+&qh{-;NmarRKn z8X7F@6Wu!ueBNv|RTracoo~h0&GOCHe!|h|##l{DF2iPbyfuFbX|v9?nzCHIh&_2u zWK#2laAxGZ0_J;oNASAvq`-ki=X173-mG)6kxvaZRT6*a+lEdJ=<)WZP<%G)yVfC{ zt*H&muD{GGw7%OGh@9t?*)BVQ>^G*2753$za=r1&E2m}R6FkmVaD&n^YciSG2(&38K(S= zobhT+2Jbu5j-UQnJ#Z`lpNss~&TkEz{@H5mv&~nUvbR&#tn*!VmEL$PRB7OEnd0K- z+DOG5#vxfCd)i;Y_dATgVc;a}Fm?wY{GBd1=zmT4W^Bxwk7?|U$j8pJ#y8)bqdrS| zlr(%6;yVJN@$4UVUNAUxrv)FKbe@qlw2$9Iq$0rYWPaiY+2Vdm-4_S?9iIl_uyqz>1ZueXyJS*dv=&KiMwk@rB@3yARW@@X~&PReS!P?)Csr z9*pkS`<~}N$vcuRcuGHf>6hvZu_rm1hE5njC-ig1Vf9%mZfH<> zo(YS;8mZ{x(88Q=+yN~@?4vpvPvko5AZ+Gq&M8{!8gr2cij)}oO!_5 z%13nJE;7-~^Ti`w+=U_)FM|)!Tf8v>+%+>M;jaFx26sj0bm8t97k5?otnQ!YE8Tmo zztqEF>qKxUndIQm%wzFg-nD6^xzo~1y|HdM`Pjz#;1R~E`zzuT?IDu+Bv#xt*0ym5 z?xNF8_~hhB#of+W4WE39t*a0}-TZTnJg@`E-MyM~hW;V=!%6$Z8`I%@AsUM>8dCVe z;TQNq{Njx}c;c~*`?4d9TmFZlv3!Y>X!mSrYD$Y-$@$-yZy0&O8 zJ9S93ycSwc>!M}V+0b&QH*P~qZyX!)j%^&n7)P?47C%N@*cKNU*k)bM`kw^b1HcB} z9l!qiQ(gW$(Jjl|?MvBeWLpU^dwge~-gk!2p<9>!T!@Y*dFSbTN86uRrKXRTAui6! zBNaQdH7|@`+_%Il!1Ypz;gwdc(Q)xgt|KdiL!||B%bYZwYZ;qo*B&wqOv$?U(O@b( z*}zgX$b`jHBNe|*f@z`))1Z@%0@L6x2U9A|>WfVO?E_5sMYaNlFK3$-*?7g*6P;rU^jC6SAyN0H*Nh4OqFR}FrDwhlss?B z2QqIQ9zOEC={W6IH>TcusT%gwWmASddD)0zt1rvqo{4DRoNZ{e+A{raogS$uq+f5I zw)UsLe&WUK#_$PGUsiTP<7LGsL@x`Z+=1yh?bkO52R)w=9IhWUyS&zZz;@0Fp1cCS zNb1+l>N_JnsD6!KqR!B_!7m>HN3tFy`+YtA9=`8RvSYY>xHxY5nssHQ;-3S%#@LX- z9x?sM^Q}8=T{}TvL$j8BrrqMJA{CpG+Kr`YzpZu;w-a=4k99lK;JCe(zz4_qm{gxiSXK70}{8sddX>(F#q~c!M^!6nS#c*;85y0fq|QYLj@QWDRaVIS<0Q*C>)93GRchBN1*>`ROeHaC-YSsUaJ zqy17f|IrKL)!5#vpu;laLCyyiP9a{xxs7Ob9reEKxz5)!4?owjzObG1l=f|AtWVC4 zRGgcH`)9$E=C5R*#-A)BN_H}SpP93k&)nrZ9+_MJvBARta8M7-l9vtO)#7}m9^Vbw zN~QZ1SlJ!Bp=Du*DX%kajV+nBsr;Ma(Q2SMC#%meJlO7rvZtnrR?0tyb25!>*MP%q zprL+-2Z~&o>SxdUzm!wE$7%z;6MQF+rDvIi-m}ZlpyfT62H%NP{F%POTMb@{z)PXK z_U!%8l)dWjCU4BUrcU+EvX5lX(^-!64%x1?zWxvGce0g*bpUWp-d~L%E4e&xT zep2snI()ao{+{N3`|nNrZ_JHUJVLultNJKwMyuLlzpSxq{>a`i2%c4b!?vs$4YK{a z`LfBhjl^GrJqR`!WC8bRD7SQTR{kt_GL5>YknZVWz~k(z4wv~xF01aNZCNuyTU`2W zFfa=5bAU0Iz8j?5B-t{m-^+6Bgz`yIef?tZl9ptT)PCNBL1*t_)*bEZdb1yTdcW@L zd$Kw7PlLCjHw{c%ABj|4089z)47B4H8To^ub&2+L@RrWY^RuwKXUd;XYoXCmx4}mz zVG9YPpS8ndZ2_z1e$Lrr*dwaZYuEWX;|=_HWemS8oAG{hzG&Q4e>h_ik69Ty_vQW{ zb@#&u$ltZ$jRpqY-yKQ0Q^5&$R35hTCh30C8lB5GLsRz6YlEXhO>@Ab%H>hc=h{fV z<-!sJ7K?g<$7UQs#!=#{UTIeuxYAh9y2fPoYLY|J5!I$(yPCEV{qaww&w@OE+{Pbp z1Mrlb;b+{EONZM@B&JkNnzSBDC@HwjfN~mc&<+#T)uSh;E$hGYm zCLYlmil32eGv)BaBKTeOjEo31$yRn8wpz-JQoMyTRQP1o< z&A!i*FKy46cAuhO@k0FzCVnO53xQc@#T@GFGd3C|*|#!qns;WEP02}|%5LPqA45|$7OuKLlz>*U|0{}%s`bN`1&1+Oc# ztb@hG?es_m_Jo`uA?tij17QwflyDHC)6O}jd^Yj&KJ4cSrx41=wxMsN!X}IoW)fBt z3RlYrb9+GuONq~N-dIQk{K(S)=NoC9bEI?L(TDRG z-bGpOtC9Uga@09{ZZbUEzS5m%kx0cZ{5IN`$`+X0xKi_Mc&Mq+*Eu$ZJ&*QB6@gpr z@2`TN)rRr~>uA!?cf*2Kcng2F7qipX&XU z9C$T0nY%i`{TI^yHc|4&inG>~(nq|-k>`UPJwfsc+jXt#$w#9dz6|}Rf%j>2^gWif zR^w>^E{$39O?b%FyvC*}|Cjnc(%mlx-xq=R3&H;doGVG31EuE4Fa<69X^u z{i@`@Co|eync*KwpIZNjYwZ66EW%kUIO`{mxivLW(QPjoJXXjhBR|!Wc z_qbFq{4>KxmG>GxdU6#!34dt*m8{H~p|cR%w_;^E^3BtgnxU%be%@_m7I>7^8*Hnof$aTq3Pp+?qkI^mTMy^{sPvYD| za=ePOxK?xn$z<_=7{2~G$J_2VeGH@z;a2OeS--o>U9J0jUD;|KAN?I#WuHHCj?zjho{gy|NtN1WBeU0`NvUcT2)|3(I z+>bFgP3Hd;{!bt*Cp?dE4x!|372$ZoWrUKu)r4%29JwsH+dv#Y!ki6+lDn;hXAo{D zr0tv-VJTq{IeikLO^9z-PAMTWH>ZTKh;RxaJ}{1)m;9eYTynUIa4_LALdoH3Lgr~s zlu&!P21534IU5Kihg%8z5pE~631fso!XWE{WSdPWy{429xSAxBOZYE5ln7>IaLo08 z4SF)T2mTbl`~;aA3po3Vu`$+ln|UVsNv^WaI6m>}Q*(wla-7iP2bGiD0mfR{-X(J) zj?C#!`=0#bJ>9vT`FR&G)Zc3OXof34BvT~ATV44fS-PFG9_b;gksAx($5x#YBL_zY ztkJFTY7G8vfk!p}n>cr7T;qAGYE;ZE`-UScjNL}E0=RR?AMNB*-^7E>Z}xQe%X?p2J~#k&3tIZ#q0w<{-EX}{!; zK4)KfsJ~WVwO8nzd!%!}NoS(+!S=Bh_|PZRW{k7k7;~s3X!esI6IUPk;J*H9)9!1u zt9`DIIr$229@yEFoOgC^bN7^s_a~-%`^P`J?UkoPW6Ielh2m+>Ua{-#nso4|ajE~e zDKB1lMs(tiebL^;^!jP0Ums(OfIrCz-s}55}l;y zflJ5U@Ga^Hmt&+CTx|NZ=ra!*N=NQ(UPLZ3W%qIyQ#faFtkpiumxPZ?U3@$NK0fa_ z5@mF%aT+TF%y{`?v)R<17o-=pAjWyBq+eE)dk{8YAnR35y@zR$z zG#^rNV|*^y1A&`0!p(Zwul(ry0rdVf^nZNc?qbh{@4{~Pyk2+0z4s;yudtnUr07h8 zpEq8ORMdhW3){}kw5ffS=$z;u=+v7c7*}fRi>;=nN38L$a93Qs)JC}i-t#NQ-$r=! z-t&tO=RV{jYy1rNJwJOgci^1&{Dw4MOPx4n%L8REbPnepOojy>2ZR4X;6J}{HTe_g zjT_fa8{(hI#Pz0(_jX}9@io6si-txUJc%!*vuLg#yz3&yeIet&06a`)-!qAK?Tqh6 z8|~#%S92}7y-}oT&ZQG3+rm9x8|}xw>^Z>hG<*VuQ0b2HZL zM)uu~J-?kd8be<(<3raxCVQ!~mp%LC?MJ|2MH|^_817}31-QY3a*VzYtl5O_MxDriy;nBfU zb-q1YHY4nF874O1V==f{U{~h0*RNJTcF;zG1wicdkJG`{mHZU#uO{8L`1C#M1 zIR}{FgEcu1TjR4!^o~?_UhjGAM(4E#7@UoYBfs%&)qML=e}jY0Y?Jq1n(4RUW}{cF zMrSo^Zk}T&ngA>f(o zN!5$=p2I&K+rD|{wD+~#Y8?B8X(RSi^VSx8GJQ@a=cX50uf+OTaoH*Mh);Yu8(;Zi z(hA#oXX~CV+j%oA`bAmN8(Rk+$+S8jDd3H*!MxiPXKs`v?%7g(ytTG)|2?hi@%FZbI zQ{_FA_*r)4iCVW>zHeVw#(z7%^2C>SbssD1#B}>U>wsu;Qa9R6c4@P4%Z7A~^YHi2 zy3=OimWBZ1+|8S5f|yWYcfbtma1 zksW4CEvn=Gf1UrK4wL>W|C84$y}$4e(j;@RZ#nkQqD{7Wf8lN0d4J&()gfPN&_DSv zUU`b}(EAJTWjOL21HDtf>JRo|?=Kul*8MTa`BPtO)Mi4-((gmd&J510x$jYe?6X|? z;`6y{DZb3VqpZrk(#KkJ2RhCzeQXDYy$K_O#-y3}SicEhrF^sGG;P|nDL?4~U%qo! z-<%QTHa|~M!!lU%!SrhQ{p}h7WfBG!3_IB>1zRaFyjb&iJ zB5ua?l4ZtUP1!JGiD8pLF0zL)?fB2*ok8+Cp_AGw2;_C70gwFo?;?E$^PGOidi%>I zlvnzG?snYHTGf-ROVusKCl9ecORp3^uy?LqlyYD9KK6&nJXVY@I14;_cE$3(#<$17 zo!uy(eYGwpcoXH1g)iq(?pt2jqwr;za=r28H1fWTyu6h1 zseC!gU5DQJgBjBpcl;A5+Z$hgmAsz#@=Vfu;!CCfzs{F`9{ca{<<<B%uX|;W!k53KTyK2&EO}ps zFMme)RKC3B4Fh}bt7c5Mx#Ry4WqaexN6G7nFPD+t6JIL*Xngtq$68u(1l~wq^Q9-; zdK5k3#(zUk;M**Z^`s{pX&s*cZX_?yC9LmZ9k-q{eChjn7hjI1Y%*Wo@}i;P-e*ji zG0&U$*k71%IOUIpFAFG_@0C3YU*=G*H@?gu@5}I|PyNzgH~sQi1N#*}HDh||Srh)N zPw#yBDS18dN^D5rwk=|Ct8$Bb@+miJ|qYq{~ z`k?lJ(g)f1I{M%o;?f5dPSKtjpYf^_TgJ;q9p>DrZj86DGIv{7jp=Ul6c5im3J=fv zH+cBhz3^~%JYajr|DyD|=J8Rhb8P7ep+_dRlypR~U&`iGbW$j)cq#Fmg(2PvHD{@> zGNwg*XD1m)$+pA4Fh;$3C%rW`i+vhc7 zO}1+G*IDD?i=5ab{Jfm=jhx2ez){V&iuOOn*+v$3)j1P%>bJDKZ)inU7#XvAg_(1K+Kg|A z29tQVC_p{=mV_U1^|nV$naL|mnOT(4*mYMx{tQx`Z^oJZPqrVvOd)}Jx!3RA-A zdrkX)N^1WdwZGJ~zu9eHbWQFfF*%*@ARNaT+VPyF4d6^|AZKgYoGIq;-gG)=isoKc z8+XEir`GCkZ2cSfAMR(Z`JA!sj~Kbn8AMHt?^k?3V*0%MD)Id==gie9@Axw)p5OQ; z_1iLKAJ1uQS!BvLt9`!lR_(`kA&TD^ei4IxwaAmfjqAwM8y;%!SNylFA@e%02Uo2x zS)O}^RdWsaxF*B8ynaygxNFE4T!neflcgmY~6QfL9Mz$~p$`$e* zi1yjOn)@hc`SEXkHFSsFFK1xEfYAIhogFYQ1k?8fljaF9;iFco?`V|k4Lf8+8g=EP zbpj!4R?~suRy2I8ndcf~GW>C1kQ@z@E<7~vmLKb&#zNu;@0t#Mr$Ofm=zTeK{|0Z8 ze4Tf@)15mS;wAO#$OQWR2W_RwgygqER-%$+l5&Kf_L z_0(yY#hY%}ON$tr_bmdgw^4tv*KZM2;g2#KS$xEA5g=c##($*^ddX(pKwr9BZSySx zy>H;1#h$J*l)Zs4`CfwOBPv?lLtU*ow*sed;n*^%GgEbG`+Ma7Zd=cH43fW#*B|`r z9DNq>s}1iQ{Yc-%TSnVjCwu!Y-XF+6+IR6Tr%Yn0waNR|rpBwYJJpr!l{_HdynQgr z${{^xBfs8s;^a3Fqzi~=qyv%eb)uJ3^%GqGvLxx*$IUs`C-7>i!fYKsR>I*9Qn%Wd3@KdyW}V&rwA zhv@&``LDHTAO9WuC-ExY0_Xf{REdAw*cg6K+ktBUWvT+>##Rvz`m&v|>O4Mmtd-my zn&Y>Z$EY(@b-+<8FpKwXUvRk%j#O_7INAY@%6!YP`}*e9J7Nu!TYd|eD)-=-ZF{54hIY{n11b8Lfj zXXLMZPz6&7xKZ1-51G8(+yPNt@sH{^Q@=O6FJ&rJCQzt*imPwdy|8)m{UPon?k6tW z?MeK;P5R+yzRVHc@hz~C55OT=qP`h-Z5Y^ctsLhY2LA*G%}wQ{p7m;;g@Io>R+us` zP*!txDPih*Ugqn3+4SLSe46~Q--_DwQN@CJ2Whv>Imj$R z)lr*{?BM@@^IvdO5_;z#zT=EMuOdzSUXpS6ImqESGUwKVriY>>X}p_`9vVicxA;y9 z@4j!+`M@076D^T_n>3X9`_}8yICv!#y?*_G5=Khb;8nQEI_)Ar{E6rBg8Qs&W z24>FiogIo7CY5U)kU1kTTKw2mw?t{G$+v2YS(6%GsIE03EPmJ z(c(}PdAIR_Q$kUFe@Oc=(x->cG&*6+S!Pa5Vn5MF8-M1vuaBvZ+#a>ssqfop9h|gc zz4Je?v7m3Y^BtY$vy6VW`YWc5S+wy7>Z^|E_*9zSb1`+7NJjW4zS}_9p!uM=LD)*z zN|?&`$vA1Z3_KH&RTGg_*?Y}<%xhxt%QIW<^7nvqLjSQ9@CEM zdh+Lo=XBo_2)D`fyR!#+^uCUpyIB@@&~Boh+RC+f|1*f}%e0)g?*xCzf#3}La;>fA zoY3-3e3$(AoPZg3iTf?EdgzwTx4@#h>v@7dek$`?_4oKPXUIq4~k z#|}`-`KI$00diJ%%GQDt#p{tz!6IvuWL1d&%P2Pj`81PyA@KLW53J78BGtt%LEVNE zjc<$U377gcdlD+OYuFyDgoo|Y094~!r z(lrNyLA`OteR$g3K)ke)J~_`Wq+gA39e3q;BXoM|{7CJqb!X3gUAg@TeSQ1b`qCZ5 z12_4hU(fdt6MSA#Pk@TR>( zm^Nkqx{h*cmv7k}HebAR`@MfQ_?L{euZOm_ba}sXCsJv?t68()>F^IiXUuw}?2Oqz znsi1oUlp?MCCgpuTo==yVDWUWvez;k-;+0fmEq`Imyz%3T;&doIgM$Ap3YUdzR&kG zr?N;>Sp90oVZJBr?;E%!-wXd}WU}P^lTAjxm!2(KXF7Y|?zWR|x)5!bG|@J5yk&9n8a~f+^b@1=#njLoN9NlCbWTX(H~u{qG9Rvjy-PK3mM()amn_DLpFu8y70Z5 zcJxh^!VK=x{VS38FMeK( zvUVr(*6`cUZ~O3H-FV<8ANCBsnSK}FNL!Chaq01!H1^hKJzNj#ETKMcx6ZFRUi00@ zH@xdF+a9n+WL|3Yg5}&t{Mwv3J)yqaO}+aW@1H+pE)lx>=8D0L zfxLmMxf`uLOa{K)bCUAqYoYuW@^x=FA>Y*DR!uhPBk^-{_^bsPeh2(N+pgIC7DqwT3lF#L;iX2Ia= zXJGsQ7+4n$jUndd7rFWGl0Pmfzs=1rBVS|qy*mc^Xk;VncGBO)oC#s4I@IPCw@#(o zW(##BFC`b+u$3S~4wY?n%Pw}?e~GgBN%_rg{%SY>=j7`?rALET-24_dU%t_HQvP#p ze!EMfC&*Xb7f2UBM6v&i4iEe!W5!fx{pCAStg$+~fQM>4f7=5$l|{D?|Md;>^=UlW zs@=&xRlE^GmwdPon-a3;6VlFw#~qnSACJ?=NxIUdT?W(;Fx4lo0GcWLeW8Wj|^!KSe?R$Fw;aoaT@>>h-jPb>%tWEX&xEorV zSQLmRhFkH~zc;d9=`+;MdaLGBlgdU^zd&@xz~X`xs3+em!10+(%UwgwP-E>cT;x}I&uUZdC$78bxF9M z?2Lf4}} zKj@@;!AFdrvyPGWEOI$kQ0CBj$C>(Gv1t9MLunz}#^wNVCqaL}yZ-cah;j8O9AEk`Bw^j}gFXrs!BF7Q z&tL7{yiMPA|zaJR^nbL_=FSNuaa&U&|B@iV*R zUdulAflnEEY{AoE_7&)awF?F^Cpq^Nek-+CWL(Z(k#Pzqf2SSMeVR*m@pT)t|B&>f zeOtS28*eO7PUGCe+NeFGczXzOoiXTtE}_mgJs##Rpp%}QmORcDjVo!KuL(Y24ht{9 z+@v`0o+^0Z1yAk@<`xT z>7mVY-+yUW7AW?#)+o79{y6 z9^Jyd$wA~doH8lCta#9>!a3MdIDfI_(+>PW_QXMKRqRh1NAS&4bow>r{jB)Jg*uCH z&SBz`ZQ3j7yNu}g6}pGM{pnCC`tc|5IY8R3Z0{w5C&A8=^Qleo{Ne!X;ybWhLS zcNJ%V0rw6qWq-z9W7S!JZsyfl#+XX6Q%~WX${SA|H@W&@-_<13S=Q>_9^}+a8LX9frI;fi>$y?nh^^W?7ButAKiY;EQ#M@zHflhjgx6 zG%mU>Ft~GFVhr)T&IooBeJee(G3SkBMyyjF)UakNs8s zQ$E(V?8c9%+rHSyNTvOSc>O&l{*5B(ZGS=cyV}wH8pxNtol1J)Jx1PM+)J63MJE5r zfPd4?+-a=O_UL6R?~P^*x_5q?o9?v5n4hEGXS5?dk2^E-t>=Hd zQtSMAn&-@+&-#oTEB&uw>5NXvxiV~)qv0j39fG@_`eq%;ZTunsdtEOmzf5I;L3i07 z0sdagQsy4Yie^C{c2vGq-+?XBURD<0zNmTp4rI3UozU}-uXOhQv|R*FgcpQiH`#u# z+WD|cwnvD6HnD8{o$-ldB>V0r-pc%_5BN9jXK&sUjaz0L{E2>kkAB!U(7kR;stK}tD*P+;`Ourn-)PQ(QBbgFRiQf%*!D82k-hOvg>+e z*mcOVYmsT!;HPsn?;KaRiD(hs{p$|=^4Qp%lz^`I()4!X04x+X7N3B zyQ7u$KG_Fp>Ld4V9x>>@ReJVb|1wZM$Y#nH@!ESFap?nt@3&<7HqlK1t~1{C9kk z76%-kq_F#a1nHv7RF3d1LeK8OJ24LJ3rkFUGr)s0X2!#VVUBN-;;Q#6)dyEoDDzWr zb)@fRB_I(<00oP6w7}9Cu+Y?0hFuHzZbF;*zby*&AJvVU6ky_d|Gl zqBPggC;41>2>T}H-Pnt8W3!<;WamK~gt@5|dbEYY=x+I|A>6ekY9zh1|AS}te9 zds)vLzPM)#-<@Auzwe$c&A=vp(H;Yzu+0Rz5(I>)~GvX!*lHE>fo;e z!g}mlx%8=f^QnA@@V$ILdxhKCE4<8J;XU>W=LT}|y|QbvfT5iAMK-Rf?7gH1l%t2~ zUH&3u)<=vdw9Ts7Mp^XX&8$(6Tn$Y1{R|B6a*hrh8|ia}y)bXpTI8DEdA9lfx6w`d z*33h9=MdoS>JgLTR%Kw5i$w_z0TEJumkK?e5MbU#;x842z+uHAoj-#A;kllDbZ}cjD4|^JgCl4`nuK$yX zNBf(2Teb-=#on%RD>~P|Hz4aoI>17I&2(&inuGc;csxE0!KYi~0|z{Bq06Wr!BENC;;rGyei=HC5-(ei zr!^h=4~_I+Fc-dK=X?L_Tg?BS=AX*yH*$kLBaG}^#F=0{b~xr>#fmS|&6!=wc*j`H zn_vEe!L8=xU$Akp|6CIT_S3*~1b^vF@Eqhf51h;cCyUapo%8OiTiFrF+W0ZJc?e!# z=d(K6z)h)d(DJF^>_K#L{H8mKpo3)4%yho@0FIdJ1L{WL2dy(Cc&Mkjo0?Wc{nCTs z6|#So6lJc;#=py6*gW3;A~9wG_|>-zmbu@&C@l>|r;6Udt+Qq9dz(ee4#qtXIzJ7a zH$vyB3$s=M)6S`k<22x3#8@S3EcPa)z&?}llmR>S2YR@Vwc7aw>DJleff(<8g!dSn zDnGJ2{d>Z_{#S8FCFp+d!i8sJuQ1T>6!4<4*(YbNvb?cj6Hr@iJGHwlF^fz>}Raful>T{d->U+ z=xTUeGOrSTKMfg@%{(lEw;%LnZG4b9^$9$5BRuphJoGzw=)r~kR@Idib>MR~{o{ad zL_cV-{EU99=3$p!gnr(E9a}P)HCFE~k1s;rmAi5-M7vc_A0w?fE7$-`+vS7g$^_Zs zH6P%=3WXcsDLXABTmIW6^kdujeL?RMx4$Fhsa$o`&euHN@KXcRvCQM`z~s$i`$A_A zd&u|0gG+5U{M61br|s=e9edjvuh+JZw#%4Xg_iLjsidvy)yImvq7K2y8}o;7m)f2) z{?&HAt?@r`>@b4sLoiwwn)iK@=e1`WS@VRQU&|Z(u~l6#m#}VYFNPgrGj@nwQFv+t zJcT`CmGnXG=uB^WE8Vd%+{AYf1Y_)R!~50Dl|wSc-Ov0V%7ix<`KJ4i1Jp4YShp4Q4 z^3C2d7x=R~ut`i$UGr1>x@CpI$FcN<-ckEy`s(eR?lgQ-M3?IS=%U3Db|}+vp#P+wUeGL)U)J(+5SX0-bMhH=`9<=jpG1xQ#mvF^C#mA5#9 zclIUZ2_JQt%N(838%PB7%W}+{vqwTRSAGG=gv;-e~0XV z7Ir|5QNN@4hquE&vVjz^f6%;)F0%8p7n-)WqsQFFe8}_-I)V-q?1;Luqx9;`Ri%$R za(lGeoQOW7`g<4g1{wC5Le8{gql%trWlv;H+3~YbbR_;R+bKK!`DH76k|9HoAv3XK zU3Gum%J+Z3K7lz3zsARbw_&UwrPmHyRr0sc_)Kg`r{(G{fi-_FwxpTN+cMVW5sUdw z8+lV4JyHG|53G#&#*LkZp7j8C{bu?~=lPINHhS-Nd`)%)hBk87Yt1FOp>e14Q#$MD zJn2N*$FG3zb+#t|n$zJ)i+ecZ@qd_!J**Qt-L*7OGf{r&oX=>z+>br+9r`N>SU0x~ zth>hZu}c1KO|sv)-W10tqTFoa(x%LXu*O9I{`Y@p*Pv@I8uk6#5cIZg6{J3NTvJq=WCBh z^DCkGSO3{X^RX_?gWrMX=am_n7xh4MbgBPaH2($o7R~b=n&)@ycWGV_7<7o{x+g1| zC;ZmU&Bs7<>yUheC&r~!ylgHV^6#tAN!HuH7vXm zKjdRCI`C7S67n4%d*UZ?P7(!P@7}|P5ncAt7Gyu;#5QX7CkJj?@AxIJ1wXv4icgA< z^V^=^?3a((X~^Dccl=3vtu6Q&Rp4iIGyX+GSu5s!LO-S0uT^KPFEV6rATnf~KX2X{ z;Hjs#UFEy(z3uAxYyKGA4_bAB;~NycC%WofpTA}mX^-=>=iJ#D10P1G$!*jfl^Ew& zF>Ksbr}9k?@}0ZyuI%^p8ylN;=~#bL!k;^@8JVxL*RTex#a7axvvd4)yfP<)lQ4R@ zJ;|M~$KY4BopC4cmFx{g%dJO4O_I@`4w0&hif3iJy`r#>qjRsGdke7R*F^u=Nk-}J zTHP#br)wi|zN1@LY@ID%caM&}eJ96j`_>cOw(m4;KTO-$Rz^uzs_Sps&ST!y^}*%> zjkQL#PGDb>j=VV6jQ?2HsAa6--rmU$<~U>5`M%mKKiAH$2A|8u9(#M*-yUj@y;wE# zzi^J3Q=+MGdUPC^d*?d)8k1}A&~oRk;5eu8G8Yffzh+$$9=P9j2oKexSgXOqhO>_y zZg`*z?qKfn>_@F8`8x;?_BqI5@G#}fV{dOx5+1aNYzGf*VS|U{@fWgBO^%E24(GQn ze7w}x;G=o&t(`hoi*RYQ)MjG6#r=b>eWvDwcP5~B1dI=3_F+DZmAolF5&4DOoh~`^AIN@3 z#+Y{}^v*BF(D>?3W({+yE(E=E1Lcmj%8F6eQb9f)bsqytxW*>gY%Iobu^=@V5bQkj@(!>Ya+l%Mg z|CK&N;VeS6*`Ye*>;K=~c2*O5cQJkY(;OaaAWij3K21ODF6QC$PX5E8_&cmyx9~=V z?lGgAPOo*&+;TX|(wSS1a|c%NYd<1AOYepJ!hxZOH$%SuI`$KId$Q&D6xly9XQts1 zq4<;3sXE_{^Ub*@6#u}*58tC&srWtSEtTZGb{N>acun!)_kDCu*5J@NyOHxx*2qx& z{zLHfZnqV_a|&hK$#M4Fxx9T5UcQZ=cuc&iJ_s#y?DMRFbFO%_V#*b3@%4$WvJZZHOOST*E)T9! z9WzIAo$p=^r;d2sOHT-|mNn)x+SIxnXAfED$A_bDmw(7U%8Z}QeI&j|7x6crSB>1z zn`Uhpk@L=-ZPgSmZJAJ#$C}Ce2N8edyta(y^K`eYB+rT$E?qoG+h6{_&?7V@tRv zZ^I8Z{IJ14*m=`SydhiU2z*TqZA^RL#LlF)z6<=qp~=f_#DShr-Xj{1Sg9#-|XLfqDt7m)-8sE}_&cdZnOz`N|!1(GJ zpW2Ra*4PPe0K=yJhx*TJobS>mPFlX(uiliJ=cH$_$Ib63j&UC7;?V2U0>`#+?BdYt z(+0;DIQ|FYECg;3ZznSTec*Nk=?e4zo-szg5am^7?PaXTXK_z?YA|bg$S0ko>poHE z%nO;n7vLkxH-IO*_xBl#>@@8AYU}w{aVkH1I7#JY4<|9;SnT3KYm2^_cBDQp23D0{ z@`jfm%HmI>Zic=Yt>)ds)C;5Uz+=YgYoeD%WcrSzZFdR6dcSTZc7p4MmGJ>nZukM-2A z*IsJBUVA5~Uw6KFeIBijp=EaCkLa@v`Q(-N>PKi#ve@e*73L6nq1N_7M?dVkC+zuY z^kzre&o@u?y*%&ya~t2#dlVS7t{Ry+sBu2=5Z@MW28PxoJhl;!5pM;L%}IESdGj54 zsQHJ^{}{S%*Zgzo=e1W&`AAazuJ+7(JC{?xkT><}Q*at_aneBj`lR|^dkgwo1LQ-+ zIm-ayWAXQo<0hsH$Hs`PewOAm3YMF9L2?pM>{K34!ZniyK>OO zbDr=7pL=-m>U-^V;l=QIECtUQ!c*G6kLUfI;h+b9c{~ra2FNZhJUjRX&knx9|G$H8 z*|oekQwBBjR%6)02X#>6r@;3pGEzQd&FB``OE*iG)%wvY*mZ_AThbv04-_C1_6tj6}!8*lk&Pjf1{oj=fy@KaCN8}I$yotvs#Vp)zZu^k;09dK8W za}nv7<=6#ehn#w5`dQjH;Ah$GJ&#((=E;|P7;A)gXT$L5mywBD+iqoDt7N=_*{p}@ zjStXX6*O`5Z}bQG0n3gp8VE1=X*O0;rr9}PG_<*o@peM9Du4bV+AJllV7;M@(jD3a z_+Bb?rE`cjUU@?s$!M$QR_Z0+hrW|IK9>U$#jI8Eh-d_D&0AE^M|dh^EE>lW2QS&I z>*#BkJn11`-fYHuubaP{Jhf^0tbx7J-X=dvyA#=?Z0Br+ zv*i(c&@B$}#LQ-McZRd4slYG%4khf#M@;(=`Kjppgt0!8I<+UM?&I&wE<`8fr@Ci2 zZJ52l2>!pk)v9UXCpmKp@%l-=nihV;`QNB?&Pu_p~Nmtuj@O?adFWk#p zkoXznAHGREDVbfxUeqS7ioM{6>AWXYtDZL?}Zs}i2e4@T_4h9T`jq-mIpH&`?2@7U;WmD{~vqr0$x>dHT=&$=Ooz) zL4yQ{2<8N^CV<=#uwG8MnJ7{WLGjWihveu9ge2sGL7^NJYY=Qf(W2NI)P8S>v@f=( z#9|GVwz1k)3$L}Ut)aCw5ZgjUO}yp*TYJw=b}lHi{l4e@KhHVOlgwq$b^k1rhYzQg@(+`*RqtYwxn*bb`I^Bgi~5u72hj@sDQjpS|d1wX%PK?Wtu;3eJgL zi`c@Zu^%U8?YuK?v3!$s1352JB-omv2F}r+${UAu+*KrR98RPEayChD zOL(;N#^J(~yl=Ql()V~rZzORiM*6lK=1=gDGZ}J!?XTtDm)C#^yr_Nuk9`ZIFES5* zO<<18`TDJb&vkd$w)ICA$8_4(rvammS#h6fS1bkzNEAF z(>dPU8)=RAqON-*_f*9F+xJE`&{p@jf8M>3ACbPL)NWtTdm|s?o6Uc^))(%3BmE_I zzH-t<7$dRa@4enr^+$@k_n)~lHvt+Gdkw*TGfn17`!0qNz+GUZn9ChF*X04{=im#B zm%x|%_Zm*DWh@wj$e(;SV(0$Jqhh}_Mm2=F!&llIpP1QZ+jPx3xbwjWb2dEKP@as9 z%wh2JNyhjA(szx!+&60XQPxkq7b^Ui`MoPn_|49nPSy|XwtMtL^ljEy!|N0Lneaqx z&hcA(9{C^x9Z~Dsp6@^L;Dg+!&~N({>(rJjEt?_3dZ(5*`<69JnY`N!EVf*+Ltvz= za~9GzX;07j(2@;;b{hwB9#qbK3#^NPo5&*4#)=Wbk9hwDek8EA(g5rGd8_woVDh|2 zEnA0tDe@y{^0qo-P_r;@aeNGW8QjHphqUWO?k?2h5n+zWht4A0n>^UUndJIp+#q#T zL5FqM%xq6K4C`J=85_CZHJ|TcPx8jPYkJ??c`{lT8ce5+($DPcPc|04acaCX7Rak% z`YC;izfO2>^0H9_7Jhh`{)fMiX`NGu;1_<$K3`4>d*;8r(yr%2#_Czd>gOX;wqKDZ z{5^SDCgYio3}^nr#!Zno1V5#$*GRYjQMF|n{T8^(KCm&HAEm+Ureg`d)hE0HGxr_egBuyEW+O(+8mAj8WfB z2Zuxk`XY6TO98|4QuF!7&ODzw&blS{_rnBF0y~?}&)g|; z&*72APT5a8ijH|HGRzTl(TCBu#{ChK1K1d8P5NmvK1HK5cW(WH zxqTh_V%);B@Qb;qwi(bv8F9@b#?TEpz@hh6?{^drJP zv-D%bXY@n%ubn=mXT&Y`{>0{=wmjTr=bx`qUsJ1nWj)*VmCtF{pRl{M$I5QkBHHDr zT{Z9`+djC9zMcDfGH8=!XQF9m;Mu+3j*qOe(mCeao-FYsAy$?nk> z^K9(JIEUh{S7@klWpCIF`JDD_@6nz!{uS5^@7}?xnGTGo zxAU$H`St_83BU7UJ0JXc$2ZrN+U1EXd_VVI_H1Wes?CQ?+eWF?j~pPj^D;MxU2_I@ z%?|JFx2mG8cxvX(?_t9nVeG{As6T(dB<(NZq2DN~+}nW-m+J6_h~duoj2jppz`1ABr~f)fJ`(vMa2Lu@9p(31;Ygoh%F zP=7jkWDnW@9kGE--k27n+h?uEWnQmKu=|&+?>h0*zt=vEwP@rPXl4WBFq*c>+WRo`MiXI? zQ~mT+=8F3XzX!h5YI(JmIbo@Fc6LyG7+xx#VRwC zrD&>U&n9uK<3~m)OOzS7)LRNqy}I_sBT){QRxh z#aAriey)*fXTa#H%OqZ1*Q5SF6ZhrraZP_BF4#RToj4=ZqyEFh6?KnmX^veSw>-1G z+0~yc;=C&|SxvU^fT@uN>+gxQr0givxW4j zoUd(#&lX(~o(`W~7QxRtVZ|o+t?U&DpRW}DHR6mJ&bY+Cj=gmi>mbg5v|_iD$Nu|K z>Ikw=AO3OrMh|lac$?!lE_>|}^11h!rc$q?i+9df37&WEKe*16jMn}BD5dZH2lsn! z50UnC@8lgs9??gg>`vYr`2Kl!^8SIgIdIAP7301Rp6&X)wJ8;== zaLP#k1-AKX>^VW=nhwOKa1YHgnO}W7vTrq2&Co?MPauEh;v$zc+=nY^vtEehoM~@a zus5D~;LY~Cv68RmMd}pWeDFdsW=Y^pBXg&NOFQ5z;(zZg)2koe9Ls)89CmId_89Tl`Xz8y(z8YEF`V)J^*=<$QuVij zhk-B7lygDLSV!mj!7=bVS#0q0;hl%|UH7r*VWx5?)&cTK{Y@{}{4Jij+0s8SzX^U$ zy;|*@JU}(@M%5Pdov)-nX|&IyytH$C3j{9G=Oy$#`IxQO=~(O8*>R3)m;R)4&Sem9 z?0sOtBf0)V`XjiMMSkb)L@A^Gc{!V)br|fGE@iLOt;5I~)cxMFqwlKk*Vi|9>Mx#t z&Tjh)GlBb`)s|)GGF#5)9y{7TkhUKkIeTY3?cd)`hvDngVbs$u`PR(6xsB*BUKIVs z818mKf6?+^zMY5f@}mFK`U~t8kLosd>MsVMzrd!?(qEk4rN5X(xdOvaZo7hU%Vzwt z7{|-8d*VLj7i^oS_ppDFx$_4aHXpz%9Q)cIW9KKfwM~pg+a2K6n`*{W;Bl9}dQkms zS0PD*B^$CG6sL{~)aX z+aBvi^i}ZQvn-sv#M5vVcpUhmr{O-Q;xNV%Dsfo@m=`26;FR9{=`Vek3K)Gze!m3S2?R?ohd{Pv+hiE z=aKXnhIW-j9b)$^_iH{*yzr1J+@5+XDZ~7Z-Bw2yXFZbZ*c@yiPt6id@6Q?Sqo~_W zuSXt@)%Ojeljwt9Yrt3cJ%c^zwP1%`xA2Z(@Jr`@!DZBI-7g5O%6g&p5j&mm)4ww& zl71ZNd+Mz6zip=rkYD;1X3Udmx2(M+EcyIW5Ac{sny>#z5#zxSzM>VB5GWgZjTn-dn@53GMm$Gs2T%Nj-K@%DjTbpOGhZF;n6$gx>Xu3tmG z4ru5E-|c%#Z5xj>B;Mh{`o6Z-C+vIb7ee=y*xrXV-9O6vG7jAf|9BVv;?RAHMb9bq zgD6k-+)U`+q31)I?!(aiU@P6=`hL0}P0;Q{?0Yqm)z;Au^2f9@Z{_5iqdm9XQkxcHSZ>TGqAxGpO&A+ZKS| zUjonPgYQ={|IEYYmOBE`KkOx+)X9FQ&Cl*oTUOu~el|$cPbUwfKH*iucQ%oxlZR>E zCOk`c&z<_4goTH3-pk@)19W-9%PhL2-VdQ0q0^l|k@3>;^c9)KdZ(+LvfTYFAuP0X z8E((@z?Q$+=i$>UZFx}SA7HzCAmi>{7l`fF$=-dA=rYW5yNpb+`7V(4LUMgNdb@j( zb7vK z?VzU9A9op&_cCKpYY}4~k8DxPJr45j)p?||=wLbRle>|?OZEeoEyoqzmW8vfbx2bM z^ujvi$n($(`T>hxC?^wo5jcvBD|pvJoUB7+OvUfqV=KIQ0Cl=;rGQ_jo>F+3jHSCT zF{F3DabXaay4aM%ZqD=SC$}NP&hl7%*1X2yv#FfLLw0&u^M;Ygm68v48Mu)~-(sMv zI&9>n|Jk`+IKGZ?{^Yi7-h{SgDlhr|Hu>4*tz(SkM@D*<_Z(|yO;I=OJM%XTdwl-V zVUNwfa@eEu#}3;uzdvtn36K8t9UGULf;JxP5IAcdlwKrjT#?%b)z=RH?)-JbcgVJF8|x)pBCpUv4`*bo6x0m#^?>*j+!sq z?N|pMIqhgEjP2aheE}GFo@7llG?J5cw#c0O>jG9Cwys6;gm2I|!~7hG?A?B!5*Jo;3Tb<^0Z8_hktOPS-2a-P8i4;&d--eRkP ze$%i8YG#en&YMk^&TtlXjc2mQPrWMB)3BfO8RCzp4br})*U&!PEL_3U+3}ed`OeO~ z2-z(6$eHL~S<|Q|Hw^8VW$Vd%>c6eLxs*Y=!{j;4I0~)(7Mk{n{D=RK_)n%&{te#* zPt(EEI}dbx^N7ByHXWUEs_g#*H{{LT{RRXY5|L5XQV()wZYwsEqW_HmpDU0b<&HLq zTYgVw+t&vK+V7d6cHWZ_Xt;;9$UEMC^?61=>ul2))>20aTQtXgB2q^hx?|~wIp6L_ zCjIyybo~N9i4R;An*UWqSLLTqpLedx%}+%KIE*|(+l~(K@HC&L16+bDa2m;X zM+Z0@zsQfjP43bG8kgESz-Hp4?dcc(i#kB?FbqGu`%+`H3xT+o^}3CGqLY?z;EeM-u_uO-8=fv=0dIiOz+Zvev3Sr zPC7^b8S1V7ypK29+-)@#G#fNl>_E>i{ZsuSIqN7(`mg~zAF*wS_j`6mZvXMcDlu}& z2F@qejFvdx&TsRcM}CfKhy?8RiENhQvS%?bVO|@a*}e|=-;O+W$IL*(`Y#B-vGp^4 zc*~wk?Yz#qM#fD1<8WnP%pQlXvx@Gv%eYHB*R#%i1U*2Qu|bbyxmk=6n>p>Azn{Um z`SwcU-DTb4=?({{tQC|MWK9~Tz3`|Nf9CAIuhXvQ!bpxm8tXguSK+f%Lq7d- z%Yg2&mNNgr`ZA)+l(9*Krkdy3YrOrl?eaa-xc7;4Qf|E5YeBm7{f`Wl@{4i;GhQTr zo!pT^+nu`ZLto(d`{vuWU4p_+@mcySvd5c8d8=f!YS?p@YX8AdY=1Hw8W0=pE?WbG z@p1RV!Lu@O;dF7f09WBPv z0vmj>>wI6^b+$oE?et5=U2%t#Q%}pe>>s2FuAGf-C-6qx*hLy2M@3J+9^~#(ZM;{g{>k#7(v1+;D3iXv1Ns^npD(GX)zpY^x|7XyXFbuH`kFy_+BOYzQ+E#eU#Oin$zJ=KO=oF{&c?PPpMt}=>=Wxsq&{ooHcdxr=DXlMaGFS z7TPeA;QRQ4dQR|a*uwLK7qGS|wvU|I7v zA#a>gx)G)+TrLY@awW;fDkF%%fwC6$Ho}=9HcscFqOEwOi zu+N7Kr#%5pV^6(n$31<_c57&t=psbt|aEV@fscYm0+FqQ?_F3;1kamg%wSb>s)jTfDaW6VeMGlrl}qG_j3IHBv0u%|4epsQyvP-A}q_ zowQ<)B5ASh=}K$U#g9q*H0fHHgNIU9R)OMP#FW{yr4PsYSP_q*icNX}!VPocioKkRtwme@f1GtBoV47=_3f9SDvv+wJ^ z-Ameh`qDBYfL>ALCc7NZC6Syhe3QFmq^wl#gz(WGnS<{nelfBq^-il5JNX${hcEc~WY?O7(eU&_xW9B-(0akB}h zBkzkYWBve@EVz;7S2NQ2#+yj;wq|=z*0-Tx?b%<$9zH>Epn9>;-e)0N0l= z_9MVyHxK?S9GgQw1;=LL0)t*S=0EPSbn9vVuwgAYb}4DyIJWhKr%dF7L4UW?T=P#m zeC;vY9ZUMgQ^2uw(xo|RKL^K#lkQ|Vmc+Ny!LbC=_r$S7f4AFS^|sxo*L2_7n@^5o zZG7ts$KD~nFC3Hj&%-e{&k_E54`VF+M&>$nrM=c@yrs~MPn`>3@*ajl-j=xLU&N#c{@Zi7XSw?fk;$AbX#&~a8=K?QC(Uu3i5#i6@V1Jj z2S}bCXn5@Hj&DA~xfP+q@M!g%><2_f+59i*NY{KS`cr2v?Fr|9v{>`flrV3^rUuoD z2xSF^c^63C9efMN63;#kFv@KnX7eK+rL@kL)+pX(8g9p(AWp?ca;{CXbz72O{%RUx z7Ms#%=G4dt^_;|||1>70=2KsWlwC6py(avwhV@!0{fS&e7(0TR5zzb(?YT{K!n2uU zga^3k{m96D$UO$@7Vf~ljr%rUV9!tVPQXrZXb>>Eo-*ZZ4?5G_6VRs9uBJU*?aHTJ z0zb#TM9%RZ8F`>s#zqab;o0-s-j?q8=kTk*({`Ja8K*}0nCMc|k@Goo(<<|Dx?lVQ zTLsQ(@VYd3m^E&D?0lkY@oT@+*D*cTtJ1dtnm#RASoXS`Z2C=m(RM{vK7%x;Dl0ql zJa6*EEw2n!+96{MdUG&g>QM>juZJemA#`(aHVO4Jx+%irzUV?54h99 zoa5kfBRKOK;guqf{U1Aj&-wGn$e$GNgHOrbpt7IRmgl8?KJYaLe2v8x$=G7iIq$)p zKrX0KYIEJ6W;e*$x4J*^w$x*GxyTdHmc5p^hWRhdyq{&V2QW_LyX0k@6Uybzvgb^{ z|J-}fwFgH8o>S>*=PG~txhCI&7a{A8DaXK zFZpKp&#k2ml+iA7ztC+y{SVV$X(is_p^XkBr9~ z8EVQR!|~=_~Hv)dvemRt&}ZmZoyrtqn0{MC(QRvJ-%<_yUbD8A8(!eqrTSw zwfEcYk@c4&qYu(?HNZk-f8h;|j4t|tt@KM|^v3(_ylxqt`&YWneGctj3hy{w{nf-i zc#F&}iGQ`{7Qz48Z`f@R`OD!+$3Nv9)IV%GcH%1D?%poh3;8W@5m-8VA?r%L)?SDQ zSK!vnchNhD|995=P095S;5z$wJF0B?H=ak~wRzHO&@;88pL&05?29_bq?`}5Wo^`v{uN&7i+ z-y@_uncR0T-%dyF+eG@Fa$oWzcH5u&rroE(y8pM4HeYxhJf^P4+TvEe^(FU}5Z{;F zC-I*r_x&eiuW4tTT=wcI?^HospCwl=??GFqB3J&3GW(J%d)BR(?}4qgPnBTddKW#3 ztl`KeEu}GwJsafS3R_N;_$=a#dwSUamJqkajuYFA4{tWm-Flc~yv#AYm3tfW4ClIq z{-lg>F0{j1RqkzqwOe+iN^WzChS6vkLzUKI}1G=zi8sc$k!%mE9f2_XX{IVHb?WCc}Yo&v*yM zO@(&89_QH`#Eu?5mdjleo#)xbE=cU10`wzDe9trI0z)}-?u?HEgCn!LV6cNSojJzQ z+pZ7I9fKBBM*t5Y07E625!G|pHM(+2xj5diJCv&viN&PIius7lCjd|b$ z_irD6f;#Pa)ZQOlC+YS59zUQgnPj8@f2Gt7M^`*RbJQ9&TTEHaRx+at8e>fpI`Rxda)| zqKzBX@kbe(O71%5{jmC6_C4gD*P5AKHqcF!EAsfs&P<#^nV)xNVl!okUif6NGUouR zZ`rW=8#0a?RxiQFWsUu7-jh6xE4bnbL~=&;fYo;DaMpt-gVnvHk^BW#+UK#4Ra;)A zzNYCmuDp1YEq5S8ukaf+4>@PMdd?XK$df+J&XW=9%9Bo>WaL|^ zh%6buCUBo=s;k#7&6xgq=Wrx#n7p!T=X>HeI`W-`hqFHK4&k`^Huf~% zV=wardztO}-bJ~`%d#sfz)li4f1Q4boFVprWx(69@e}(uY?fGusTE>R=g0Qe_=+uO z{>iJh{F1R)OI|-X{vk4y@UlFwsr9%+>kBCBdh&h9JpLwoknP?FhqiRS71CvQeGzAM zMP?c5RSkJBOl!^Nz6ZJY<^${wf5@NM4t|X7U`?K7D>^M6dt~7`8>kPR%kiV!Z6L$5IUjlRq{d)e&Y25$AUCaR?D2X39-R+AT)ao9VIvm4VdTt|CF_j(88 z<&?{rU#r|2%H{6eE%Cfdc_C+<+?sdD4ey4f|Ez5+irl2F1 zbChzI?Lnn5owe@n$vK;M#U*|rZK&qVj?C*{K_BF{Ej-%K(WiX&-LmlVJ-~5BF76}O zPj8z-xfSS&<-G@k`h*Y38@`TT>Y62W(Qdabyu$iE{38fm8jhC)*vci8qDPWp5|b$!>at0x~Ye1Y~KW1k@O?xx4S(*3EA zbWR=S@R-HkEt&1ialaNBBp(@*c69a&U1R$_?1kbs)Q-0IbPo?yTjYLqf%BjE^Keec zDX(Uz%$w}LgTK-@cfb0YBLrV$K6v2kfwl|Lzf_{*ou&c}??D$$BLciFVlJzP2R)6v zv=aT<32?g|TuU{EEE_F4Ji?Oq0rW0%R{TA5f}%f@crPw@=sqRoDKnBY1zeN)WQboi zqz>au68_Zw-ZnFtF$0dyxf-#Z*bB@WA64AX)wSQ}+~wC3K2G23&XT!=`JH|TG|W_5 z7t9*ra{{wZDBBH}zHnUZJN>CTFF5@qc?DKgoTrg{KqEr$XWBSq$>r2r%iginU5EZu z@J#NZ6#2dhy}=p4LhKgf`)9U|CN2-XmI8k9BLDN&@F3!u+=%DBU-pNDx4lQa)Ma2x z**LVTEq`acn^Np>@|}UUN09d-+$mI{=~2wf`(Z@Op5)+)CfFg z`g4N*h<%m;->lKL7w+~?)^Y!C`@i}Bp#5&Vbof?Z^kr&0j6sak^I9(dfqtiC$|t@g z!QEQu?3dtcEqngYu>bw^kJXkA4{z3iV-{{b2t8}uYSClyfom+@gC1M3IqJf#A>GDe z2xD>7H5Nxm{{dt1Htv5KS9i3_T~WPhwkKcAeb4T@)j#-^(2e*F=*Z1e{VKJat&=nF zq}^!C>$k%*AC&P%H&T0pEss3~ECXM*zyBS7Cx1BZvv{qucPVQMhj-^wPhWh%w%ai3 zg%6KFSE@d-XuPK5qd2qwNjyB5d-(<_)m{fbG<}Lb;b**{t1Y!7)Xo9WbmK=| z`MGbTGymV5{N$?x4kqPrZkd&jkN^0yczhpn zhup6yYZ@7gCT%N`t!*pvwA?P^vS0J+=h<(OIVPVmNLAe3Ec}*zaXF82SY&c|B4>mx z89N@EAlCAh+^XP-l70uguODM3e!t|!o;sZ|G5Icg>S23aUJWxYx6B+O+}dkr%>{j4iOv05_NGkM-L2;%(_Xi%Z7Fk!tmPxpe!gGE_apfI z7B2V3gUcve?*6@k?*gMK#@#~)?cluI*}TsUe-F^d{X^N0@B%k$ZyVbq)&WiQ?Z@DR zJuln#F6cR?NV?}q_Zl#j_qQedL&73MH4_#blQ^-(ki2ogrEsrp8{}RCLLXPlKIRLw zJ(6kbK7U3Y$6nXM)sd|E_{--0Scisd4q|)%3+{J50QNCH8S?i zT1K;BS}x4 zFKGL#r{4Cz&=#8)esk6=~!<6Z;z$#e@pUMV>Yn< zk5)O!^$+1X`u?=14a>%22XQh6S>N;Y()Xu{9aXotdu&@^*-u4Q{ALhb5uW=#{(NK; z+4r~mW!tPjVcO?v++~>1X*%Uf+l3y(@VodJ-rAzfY@tE%LxXFfJ&U%%qh!);(|r&* zgMB*YqAt7m%+qXV5E-gxTO+!yheZ}X#Xh_HTGmHjrH^Ylvk`>1&w}rZY$kGJ7#T7Q z|DQ!zc-Ue1-^)K@U)JV3TZHep``4HJVZU{u;G3%cX)WVdjZjTX>1^{1<`m z2Kpp(fvj8Q?gZia65dI^7ir7;@T7O4@%NEqZTWO?{WIj_&Z9lDei6N=%!L;*26EQ6 zhHqw)BiqZplk%3ykb0BxPZNHD-_0`}`Mx_`PaQUQeggl((bt9BmXa<#9(yqC#Kz!;NiR5( zPaBpB-O-1o&>ei&iVH)B0uL##nexX3#jeh1&1c;)78)K)ITzr5mvWvb{%`E7Z@BJ) zwz0HrEahzA`&imHma^wjw-wG0%orO~Gg6hoyc>B49r6^$Vb9&tHt;5kZ=(Ckz@I=H z=TUY)>U{*9%}3Ys1h&-iq{-v&O4?V<_j$VfyQyy;d5X1rkJYXOt6dvum-OvQz9kT! zsuGZ+BM)U+yoP%~ssBpq>BrkH{fJvexR~(E?B8RnGsCt^RITf1!x&)llB*q({z@sE zJWF-mi9OmNFs`AU0?!&rOB)gh%UC#VY2ln*KjNkCrPN)|n+ge(Ep3}ecoS`Nw6 zX}6S}P1&+$9Zi`6hd$d$S@G0=O6{bqQ*I~aj;5^%Db={nNVevSF0`7XP^2JKEChMjqWYLNDb z{!h}$U)D-w-5vJ2o;M&GUcA%JlkVQ5=I(ju^H}<~y6&FOUGMBs&(eF;YYrY^?|CPC zlp>Ru6E{2*uRgsuL4AC0_dV)02a(U8Qtz%gIF$Cw+EaLr+@bw>chBEQ`kIK{zMgy3 zzRvOJI-lgW#ctGZk{pbYJ>Bl|x4`hw8oS&Y?p2U^R0%(ZhvYG@*Fwu?8hecNOLTr2 z0zc9;iwzetTJ35(uiR}=LfK9k0rWyAD?`>E@TFr?W-WD%NmH*1zn6KSA9cxG_y~0e zs5=q(FSF|JXWhA({jHhI>!jsd7Gv@QaMF!q`(t{avH9dSY(4K_@0&4ixr(&`<=64n zA8TaM`%gs%X-IvNH5&3j^IgUTe;Q)joJ#ui5IFK3aD;bwM6kXxzv>8}On`OVe;{{uXzlZSEf>C<8fcI^I9b;W zQQ8LMa0UH9CbQ@VeSwu0*#FO$ZQfKTGVzm{op;tt{xGt=q)P(_D*0}ot+siB=sF7M zi+iuzu^kq882m|H&EBr`*OFewEgiS7HG!o6zp3-rdLT>ZKaDnY>ip3GrS_rgp9t(v zrt5e3Nz+2#VznP!2`o7`jX#CH&iU4o!?&OC%@vm=aWC3&pJj{Vl+m;RT--@|twZp0 zj%EBC%w@6v(u(R?ohJtT}5`@ z`b}&qwy_?pvS^m~3@O8=-LAVidfL&*9QGa3U4$KR@3T@}Z}Tb6^!|i&mOhWW%1o2_ zV70L`z1Y@)uqJ4K>-X&4!{-mp_w0NV+i}@HkaHEC@STJ1wSj#uLs@gN*o4UaZjOzM zoOQ}){QN1B*QlR+7&~3)w{II_`>hpuKT!6uWo?_rJXMSS{KvFI#w@bXrf(Uu%NR3r zR8Rgps2BhB18*7AM)+$7_aa{jA4ab}`UverHf_jT0UzUA#tQaQxrbSJwxsJv+y|t4 zZIaru?NXc0P3Y15F87?quDt*~+66BR&b+{}Cl%R3@a(m6-f?3*Mb9X6XJDT(LEt6w zf8;sa@1b9A+LyVFzYtKb7#!%0~h3OKf(FV@s&F<;A?_&(l^-ytleuYkngWTNA7jL zql0tuwoCyxp0dyJo=i58et|nvoIF{R?fUYOIifkV5s^r?t+@tS_c9_l|qzaO$c*BAXto3c(q!(RlZJ!$walw;FyZ`tFIUX?8L z`xI%I@3;P|`ly#FM`Xv~>FCDTqskX~6*}M7*+yH>wpW+eT^9X+rw@67H^~HM4_NK$ zt`BjyNpz!(GuCtEI>~HHvuP09MG91%e zH`>?y`x!d9h8NF8USb_s4{p8)efH4FS$poMt&`(!x<#~6>*N~DVPb0 zCtthuo^!AV(0A8lq5ElsM>%)H8r)qYZ63r}iM%9l%M1PPWItZ$SKe9Q0q+XKlO&yc zUa{6jjAK6VwD6WRXXx?7mZqD|T<{_N<247f*vk?-e*dvG2V+Ug8t9~V(H!cdj8oO; zF8&Poxbbz}IW`Y-*0#;}*lWv$$KUN-+x~@i7*4t#Yg;G1%ssy+-MXQ=yw6DI=$3zF z-M?b+R=t58t_Pdu-sfgyUpAe4v}(9VYpqAET8mww%mHCwj(%~~T3~MS)^j{>JtvG6 zIa}^;jXV^_o(y}q;~Tl3?tYKC@qOm&YmxEWu=i?bE&3t;+xXkyku&k}^%>sj7pBLb zb5^S1U154387g*PWBLy}YwbGkild&pho*aLhK?C9{H(S6y(_Zt_cP)XmU{0VioRyb zCTyN-1_h>vLqjKvPU;HozFr5;NIONZCi2#XPxGc{#0)*_GQ+c?mT%nU(=8moCTZaY z_L^JHQL9838Bd=0{j&xnsO>qUuS%GFl=%3__MG_h)Z`3#ioOz{4`}O%4Im2|av3O74 zHPFtO2tJ#POPFyvLLJh_BE}@c8~@UUpJd+mEOg{Q16w=n-mdM)yl<~(I^&nzS_5r` zV^cO_gV@@F9F)meq^p#du={Bh9X7U4xh)>!C6AG^QQH1z?mc-6eiDPc`d9S&o8)X7 z^`O&D4lfDpjE}L)@^8ugkacoyQ37pf58RuEK0AYQFQeQ$SKX+`|u=*759kOvLcTLKDbVbmRHC`fTt;(pDb~e&K zGiLC{4POXUgJadg2Q9uwo-FRPtN`W}v4gF4^o2tX{>Z-SPTC{*;odK8B2LEhL0rMH z&!TyG6V{=5u}OSW(|nUn^D|hh^rHD2Tr__r_d*Xzg4V(R-!dQH8fR{7@t#v3e_o(^ z^qPc)dB0UFb}%mCxWKC01|oCwer@V`s@yuif9}0GN1(M2zKGu4ID1mdWopL#&>H78 zlP~+kSRr_DWU`v^5p*v1oicAECs5buL2B}4pQNrZDK}$H>_TXLlB7F2%}%?BvCTHj@C_tPKQ zCl-B-d^_|gcd>!*2KbxK)_|nrTzzhxMMKGq*I;NU85&B~G&HDwA!Be5SjyT!+}j!J z2>l9jcEGO&ZG4jNb@*ST9Yx?vlg5`O;J$Wg`t(%qFl&FQ1^5<`E&<+0|EE8K?W*9+ zTJO--J5K!npVzDqnE?3wZ{szbojEODBkOQkSDh}e*~a?Tp<{>Fyhh#sn|RIFUHp)_ z$ht@OyTl2v`6}*by@@M*JI52b_oI$~{4?w|pdC-^pP3`tv1@-HyY@Eh+CQ-7Jfl7g zEy!Fa=Uaq#R)H7k-pIWz9dBEAE{37GES0=*!-s1Rrp6?~v32J^#G=D5@g z)bSh8F@G_p?U{V$i@RtW>$&~W!`7SCYXmC~9o z<;SILG-J-*SkL_VBDUfg#*mk;fM>h%Joy-T9$~&h9?g|?^-}7&)q_nD^OC)<-&=3< zap_O3_htlU7m*&_UpLuR)->oTyRB)~)f)EsPF%?smOS)F{7dl58dC0?a@I6E{*Nk? zwG3-vYfaPiZKIdHhkW1sE$?FGv2}1|F8>0Te}c=OfJZxypC>cf0(XUH&qce}T(C!R1eK z`Hwy5D&OVb?ecGS`O94X1up*tmp{qnKeo+PzRSPc<=^b`m%024T>c3zf0E08?3=Fg zUH;uJ|7MrJ%;jI;@=tL2lU)8|54g&A`FFegn_d1gmw$oFKf&csa`}(l?<(Kr-|g~m zcKOR({sk`o1nr-Azt>u$9lQK_>%F51cN!M$EKn*%Z0Qw0@yk8}Hlmha>})1!zu4Jb zq5XfuU!eU*@!zifV$1uS_P>Q+HU^~3!}zb)e(vfUf;?r#{~rH-?SCEr0GOqu{~!F^ zp=kMkjsI!w=S=Mo6UC&Yc^QAc_P>aKkM{o*zmLU~qvAZ8qs{P-?|6jU~PvHNRE~gHEj85|%{C8;oqxkRB{zvfd z(*B3>|492E#Q(DPKY;&_+AsHAzN7t{@qeQI+=DYD5d$e{^WFG|Y5!gL$7=t2{9n}m zb@(~UWTpQq{>9pV8~&TLzZ(BK?dLr75ca68^yT=U(Ed{V&uV`${ui~s2>)-j|0euL zw7&p!wf{o=*fyz-?dKW8)Wcxs!$#shkE%1a z;cxVquXv0m5866H^6S{1W~8V>r3w>CP&QW5o4X9-al@6Sg8+}13`?q3W10LqwhuQ3 zsf(4m*jJ_kQ-5n^c~wTFh*1+H=0I` z@i;tSSInq7Q@s-N2E1yQY3?(}8+tkWantGvD$VCw%FT#~2UC^z7#sR1Ia-7)jK>P3nKcNIYSv z7MM$4O|f9}1>kRu0md|S20ZF5BQfGp#~^rB1FSs8W_R;t9Fx>5WC07XwRpo2{?>b} zzo5!sQ={0KdEGGCuVGBtDSg>9n|;o$UWs|w8xTw(?>HJK4NTnSBOU!lAGq5GOcLvS zYO^)TCLRTq}o^pJ4v{I(&kujvr?&A zPf{dS?e-AcNFgyW5WLNvq~;iP%rlA#yh*RbsK>o<_(pG1BMH2cz?-z21mcbOl4@hr zW*^>KpJ2ysA06Bpv(4BOYwU{cKHgJ}3lxn^j~KLfA1La9J`?G|A>-op5Q@iaVMx8^ z%U)x**YA)7eLBy|mi)L^U7WPZtL7z>r`m*(?S?l&7P~#dM)-AX7hIjL)b!cgXqGWy zYmA^&T?{CdNSjX>WB0|-?aI9v19*ilxA}aJgVR296DVwT=2(omHP&d0>1=?M+hGjZ zW0;6=`wU^OZ+LvWy#T7%s z-h3xsHTFw-r=RgkzphpZPWjUlp@JzwMEi_UTRp1Tp!3_{6&|D3MFky#2e%ubisH{a z(4V$9k*Ur%3jZ51zCFamXLK`HztxWEIdP(FYVZB)RWr4#b+9O!acCx!F{2#U>*`Y>hKXUK=OL z>*5}!FzKVk-{|)gAosX23jWw6sMzQHxZEhTWsEwmFMtg-8HFfgU-p>0W0@goz{j3s z@p@B`&1-zgkH@N4d`TEiMq$0{|}m!&4a>E@X?8o6DZs}GpRUu=R;v#spb z_@1rumCE<;;(UiOK_*JG(J=NhR=N>34$#zMv(`|RBmuGZ7{;!yB$OlV2q+aW^Hmn@ zC^RdL;?5#;J&ToET>O@Spae#>7-pMc9P27X>KUx&iQHSQZuG18b=BPR9(m*)4YTg^!6AtWyvl zZG7t%3yiuCVx?dKUiEI3Kp*NmxpdHs;CT= zhYI~mR{1MRmxoGALjF*3MQEIIB`+#24&59q_6JJ}{RP32lF~~5l90cuq$_*3Ur|+7R$5+3@sdt0UNG;f9NmxE<-uEKQOuHH!7?>|QAMb{ zV*C=)mlQ184P5j~qQdTpp@iSWq4cl`M3c+Zi*nw5p`A;_~9sCBb5=5WZv<7hhFcQUp*= z6vs%IACUm3c#sHCv;7Avjo&91n-s%R#_3l&)Ls4RUiLLPeV4A|JIl|mxTdJ0 zXi0HMl~z^yFS*2D8P?ss;L?@)iwtIG#a$UB+5yLc(z3Ep;g_l^ty-Pf?2=y1C=aeI zs_fD8oDc|FRC4pYqUA-E72VstpcE2dp!j?hh}r#PZc!x-mv(gaCnt2%EIq89O?JiQ z2A73EyCtQ;^1`{L1yy!!S;30lku%Gw)9y)b>D=a zXQ-l*xkc5XLc2Hqv`hTLef+Ce`}@u&Uo+hOvPf%IaZ$mtp3Shn(2`#51MYyKqM~Pp zSykl~rR6!=F9}sw+F8R+zOE=K&6Uso;4VX|wDJ{I}Hx+i`!I>^-0E}647gh@4P!!-7s}t1^rN01Z$^JP3@hsEVTH<5w~Z!|7!1U7ok3 zs;Iayk12%8F(DB#1fPFpQE9P-g-8j-#S%lI>E~5kbY5Xb0u`uhIujtM*xwK<&a2?- zcpG39YHp~qAS`)xg#V_}a=%JQP)>ry7c7wJUlj-Gd$4?*Ee&W#>978qii>UzS0Y?2 zucA$*Us_3j~wB%9a7g!^eSx9Nh?Vnd__sWjD$Zz4xxSPru@mosEg=Jn_ zR0vsAxZ>0e^S_k0VBVt3v*+h!&;GKyL3ooBfj@Kp93p2zSaxsx*|Yt{rML8o3)6Ta z)t9OEhN_ZfB}ii8Ur-zhR)okLEC`7>R_-qe-Qtv0R3h`E4pjiR;zAM6vi-Lp`pKsf zM8#ryh2&W5B;&i53vWW0s45TnEtD<`R#YIHRhIgt2lhlU*G{0aOJFc1NRl=|_=6Rz zN(%fdszOy%9xAa=VF~kfS7W4`2&_dVD}%*Fh2zwCs4cJh!YSjGJp}lK{;c6}Jd16( zFGSpxdD|MKg_Wgcj^A#R6Vj8E6U+$}go;*%u7Y<5Zw{$zgXJ@6qMPBA^pn6i ze|n~0BeuWvCK^m5^}x8~YXMoPa2!Y~C=n`@V$xN{IB;@qu&CIIps3tV*aPO95aTTH zRY?0qE-w#JtF*#D!GBYE>2iN(pGZLAuob@)Ld7>xs3qWo8^J=EjQz9WkOEV_E-$L6 zkYWV9?lLT*6Pda1!gRK=ei7`0R)G*!L1|TSp%uki!0xEOka1+-gCqYra)azU`Dyr4XIQ>8Niu!oy0=vr+lfN(3UE_bF|9xACCm%xb2%3*n_ zjCM&?c4cU}|CS)bXd`g2#4n;FgIgXfxf!U+cLa)1^*AdhbEuPTzOeGs$T}+=Dp=-Z z{+Ba?-%Qn~Snb7`8c3IFPF0~Ufd4u)4_*q|7Obc$63)!vmLTO9OYbwY{SM%OnIwZ1 zz)L}s~A31s1^K<9q%*~uNrz<|2m4d^Em{zI^gmd2-vUtA?u)TztYw`4Xr7!^} zaamaSp-iDCPdmQ~b|*8E5XZ@rWmbY4Ww5PMU?cbhmFQWdm@2zU=v);$6k@ZCamrOf zML{@JSOwvpZW)VgW^aL253-CF99$Of#a*j?8Mz=synMMV=x-^i4BHGB-cwX9^WJ!s zZSf18)$W(ADR5=9_>+`nm0)LcCIn$a7HGTA2EqkJuP~SIw(kqG6d-fj%T9dndEpTJDw?yXR715(D6)jJkuS|497Ft@r-di z7dRdnC9C%FYVJfecaoYrS^lY$E90mTqQ0!oS6@^&sg*P{q?2+>mn>x<#`>9r zY_By7b<&n=E*__l+B;bS)6w!EB4Q^Y%M$WSR$&!NQ;$=kh>pTO7L~}O|bk+E2mwl~fUhcJdH!EeHecq(&u2XZa z%$azhv={tCdMRI(goN;ap%LesO&Uc9$uQhDyv*>P8Zwkycl2vh|h{-b?(h zdky8skm?Zbge%#Gz)iV|uHA=r6gM5$KVPXV+{balxMRP>Ru1lN+&Wy*k2c{puH!g+;aolCb$>hNPW2JU#88t z`CmazE#LFl_`)sAXB!xIb|ISwxGf>25+5*>uNs>c+(-?3Ah@sG!_GDC=5Nqf3ExNi zaEl+n2=<#i&hsGU%?yw(GF7C^? zn{ji0N`Blx6Pjz>c|T|S88_=!z@0+_dtRmexYY;wj=LE{2Cw)?ZEY)N=0xhPmmvXLL2bLJ@z5x;5Kzo5AFdlqZ#*Q2K)qWVt-)4R!zzo zv=w)35@q3@;LuSn?!$iS!fhGF7~?jc&sa)00~p~(MpGW{fpO&f7W-4<*~!8^G?_o# zho?~%?mN?g;kWrd0~q2qUd)aVZgHle7ULe9X{gn>;aTLtEu2jn+{7;#>Mh*1tLf7t zhFWkPu)|$_J$~HRZ(z)Et8WHYxREe8ggdr~KH|3EHshXHNgcSpwH%8;?*LLIw#SijAW0BJ%B6QWTU*wi*Q+^1Lw)JRh%O6DN{?qVi=;g$|}t z-i5$xh8ntlhVp$pLwRnzh&EiRd?zlI%QTdyGN2NQXDXk67A9S@m2qH>N?3onGV9Pu8hF#Dy8~PWi;KXhM0GOJ9lATcbD=eZcx6u4dBW~6~F%LDt5tU6(4v2 zyx{e$)!zmVk0|qvTIG3p2Y9$c`4S&fhVOA;^d031{2ygJUdNd3RGzW*Dt5{f@Xsfd z5#FWZ=Y3BZb>CC{M(tMSfhU!5=t(vBt?#S&wjU^C-X7&KpHarXXOwr(US;gvs}dR; z=;yQa^I7HD_AL1DL*=RYq3T!M2tG9`Pw|hLTYjR<#GfkD-=xgIi^?N>ZT3sbSnv{j z=_S?g;$Hx}UjnmV5%-Gnq`#`-=KY#6IH+J0@aRLz)AAc|_H|`!eqDJV{;e`{e+N$e zUiEw94dos62Nkp656aW@2k7mO%80=KcE72NJ#Q*+ZL{)Sd{`NUhn44z!^&IvCzY`G zugd%K+bUsmEAvgOik1M`2V{(KKS##8hGFXrG~Ysvv#!scld06yYi-dNFP2_ z-Wxws0~UX*Vp~2|p531?v3{!J8atHXr<-AA#EtU6M?Hq&_Zk?i!25j0nXfZL7seWA zs5qnlJEq~ujfY>x8{R1iMofN!5jQMREG*&m{SBkAzY%u`UcK*3Bkov|Vay(2cn=LQ zd}U`DUNz8&89NZZH_(Vr=F)+&gAGqDZqr~R#y`X`rVKIEdfeI}MoilfOzTpNn544} z&*F0oU*$07fZ>Mct>K{1xrV1W)rhV18(x2!;eCU@Q6r3)1tZ{(BMo0IbHRyGMojK` z@YnOO-pnv!Ue7>Q7;D7c$b)-X>_Ti7an{je<}&NCrT~<+gEvg zq<rONM)u)+0%}I~@Fa69SJ6qF_ zZFf(T?LK}MkmPp=8nWDrZ1?qY+ugIycK?p$i2P!{YrE%Y*NWud-bOpV5&j}S2M@op zr+fHH9j?>qt;GE688-EYYo4_8bN<)*M){*^;@CCejTpX;WQoo zstzN5Sii67@JJortiy;U)^Dp0pQpnQ>hKqI_}e;sz7Fru;dCATFC9j#v3|RBc(e}x zK!?ZZaDxsb_E^9DI(&f+|6GR=hpgYLIy_#7U)SLYI{XJ6Mr^WvZ|d+Q9X_nXlXdvd zIy^;(|DwZ)Th{Mw9Y*Z3en)h8nhv+>@N^yin-0&=;eY6GrVbz1;h8%8t_~xvS-hMQ8e7O#PqQhA_+@ZtSI&6I3#Trw>&(q;J9llD3 z<8_#2r}gWn!(YaYpu;(KPz}`Kg*rS)hY>}s-w+)}B(;8L>+m%? ze2xxZtHZ-}c(D$r>hN_soTkIq>+nb&&e!4dbU3KP<8*k54o}nJ0v!(MaG?%o>o8)l z^~=%Wn{@aF9llwI3w1cG!^?G8vop0)hnMQ_Yjt>;4%g@~BDM9~qQfOR{E!YKYFod@ zbhu21cj@p79sX|}F4y7j>u`k*Kc&N!I=okht91B>I*izE{eGmwx9ISG9j?~l13HX2 zZ~cCz!?)`2OFDd;4*yDrSL^UW9bTiuztQ2Z>hSM%c&!ecj<744)4}s?+kDXz}9cr z=LBoDyGy%!wR=FjuV}ZC=LY2Wh7PxA_k?z>r;7NVsMDorca(M~X!m06W@$H9yZPEJ z)^4?Stx8@0Ue@vJwfnkuH*5D{?bc~`k9ObE?lJ9ttX*@9-LGWr`n5Y&yVJEhTe}Oi zd!u&4+O5=XM7x``yG^@~Yj?MH_i49DyN9&ftlf9C+ooOLz4~0Ic86&*p`5oH(gCRC04=I4@LQPKt?hR;tJ=&e?Edv!u$+ z?wL&4@z>0sI3X{upt?G^q-f>DiPP{G2P-P_Dp!?-@`_4sDxISu+l>6AzEV#jXGKvT z8O+++GjxVt)kf-$>82U^b{h(d7pzp}bw+Jl_coW@vRw6uqoKjPva0e>-pZo#%Bob$a0c|~bSu(+slRo==8Dzf`ir>4z=0770xWw2mbUO{+S-py6P@h>5H|wE13DmA$VOl*q)kdpw#R$%tn-eMy1uH^ovnn^Oh=rBq zMI|@SDh~xKL)R8nhG*Fkk|4>I;PO!A%vF`43W-nY9zV|-bot=7J}kfDl4)J=FA~(M$o}liI_93pmcdzusk$p`SJx<7A%(* z1-cb0c(gK90Cwk5ekhOh%S%hL=Pj8yXO4WU440SQlIO;8Fq~4dx|cFBPqKG5@05#K z&`C!Vi%V}NzePr~Ce5L>Qq5xL`@ar?siAT@1^}eI{C~f^3xj24p^`$Uh2j5biB==a z{u4!3R21D@;xw}Q-!E}SUf#`u3QJZ2O8E&mBgTKA;IgWUFxXSDY>qYLHUEJ!XHA@w zbLGORdD6zs|AF#?3%knO)~&p<;!`C>q0SyeoSTGTDyw> zkG=N+kE5#h|0jQ1iUcT7pg@5DRSVQ>QVJABP1~eRY?_89g^HDAlifB;x4U6?Q&I#C zSfN0?My(R1V$doT3KXqaG)Ta5iBh0q(IALbtMo#ZBE3?z>i6?GpZ9xnGEGZF?(^K= z^ZcgW$-d^C*PJtF&YU^(ck8kjWMk=N@uW0UZll|j=h{-)N5s`EHi9qOUBw;rGFWA1sc<6B^Kw?-nkbYLo3Nty5O%lt@!5 z?Q-0uq}4>)yJpuwcDpH8#nLH_-J{f;NM&NtxYO6^glHlXjXK<5=wfL6O~$#5^%y-Qis$Fg=Sx5}O&yI7<5IFxk|i$oii#IhM# zf$_z0m(V&tY-wyoL$lj6skXrn%ES_GUYmwa95Syy4bw!Bjeal}YO8W)Fkb_Xvk|vK zw;QCf#5;+$#JhpA>(Q+31twWOg*xYKI>`b8r<+^c+U^2N6xF*Gmk;Iy9gVz(U{sL5 zu(o<`aBjn;Q_gE>(C-&ZHzq2ZO1&$;y2#>Kc7^PZ>Pi~o!6PRI$IJ}w%qtK6kyjNw zn?FAmJW?=AcHF^Dg|lNpa!Ox(d{P`2A%rmr@~ZlOMWc)*%9f;mBD@E;+aTOA{MNg5ELe}GgJNy zewtq{airhj68zh7)0a!z5^uJg-f;ZfNNaUug>1B+JH9Y*FQdxO1i#Hs2K$Z;Mp+(a z#I(m{GfhZS(pyj-$wubK7SB$lqQRF&T_Q!8y0R)cD=l$?&mUczXp>f{BB@!52K!E$ zC4DvNdvd~>lM4g)HmgyQs3lOF%EVoZx3X|aTzX*X;8%wxf?rM0Ek?_xN;+l1z$x)$ zJi9=e&rEG1l8gm^I8Dkz-!3%<*$G}Pw4{UkPMRK1H>V?uv#w}2o;)j_&SYyM%csYq z^A^`jA3f+gwK@`-^o3I`MzH48x)sZsQinLTI~v_*++SRgh_p&OTCc6xk50chc;t-gNK!iPOJc!26N3U-bHUF? z$Af!L9kgc6t*ekKvm$u<)L^u%S1q7SuvcRJWAx(S(}zZbTMu0x+;M1A@Y6%3%)g|| z*e&B=bS!x2ke1-CqUPYC@$qGC30YWf3Bg}ZZ;eHkqI>?&(<94Wp=l2~xc=>0JkK7I zjLwy9MzU6)!kX(kIXJXD_~957z|W7gg_qSJM;f+>eaFmBM_OB?3fD<%6bt_Amf#@hQ;9rvu&@usiqc>6ab-XZ0|kKV>@mCKf?Xb*l>Bqdyzj4xg++sVsC zRzAV4N6Uunj*6rfxa#=N(`F^&OIotksZ=Zd;F;4=p(~|QCu9aMObqg+N=$EVmKBjo z2QR)&8jD=?pB72}?$BH(gPRX))rQq=ds?v5lTmk|wC#kTAT8Yxx82@%SVj(O+=>pK zC`zOv(RodmO9v#_^Y&nLd2mC~eoGYm&R?EaxjeTYJxuOj4Cj7FDED74@^k;J zntNvHv7)xDG*wBfY?v;PMI_~?8&P#T= zvRnJq;e&^YFP{9_^l_IBCuUd+qGoUT7Yvizdx zqp`U>dPG%HdS^-LW9>dxc26e{7Gm%m3ojU$Ses5Y#ezu&0=W2KRi9ZJx9lq|rX^75rX?jC#b{NRscgHf}CRbvOEb{r*p z>CYa;J%sFt=BA>tV8c=M@vO}0{-c6?rtsyl>Bw?9hY@tjT-W`No9nlAu6xE72CHA! zJazs>@|178t4#3Iv8i+-TA$K#PXwPB7v$Hbr2iV7*Om=-j;%_HdcDkQ+h0}P{x==( z*{9=G|IqQ4f9kmN+I$&zUzaa4&cv^h3|7aN$uWI!=TUAEACWn9eL~}`TB+lmZoKJ} z`n}_NwPbVldKx>9!tOHog6t=^xEOlYz}9em%677!K3Wz6yOk-?V9POu!I~R%mi;&C zxbJ=)Z+$>!UuX?PCU^$>2{XE-;a^~xAc3_@vxb?#QuDebRe9tSA_yud-bVHbX^8_jf+HsmnNo` zwzXQrlL`JRHL~+Mi8s1F9Z6;qZOyS{wmgzvIwRE{{LeV-pZ+$^_Rhhz$1>N!i>FDO z8r*z3=k!OJQ;*E4FxcqE{W{kI>GPD!zBZYWEjJTvJa(|B5v)8FJ64zN9j6us&pRa+ zJaeqfx%YV8>Sre6%}ZU2efM~2sWQ@0K%QPYR=S0^O0QzKOK#8gF6kS!jBF#Xi)FcC z1YbT*x=_;jm1gK`(yHzFv_@k)_wD1N!B?dRGw>Om#oo_pzWrX|{|xOFUYqL`dXX~0 zr=*A2xmxGY<;JVsxZ91_$T%3%)4cz9=@9GrtC@0i6>|%C$9O3~jd+OLQ%UFW*72_M zc}YBxm=PxYHEF+= z8TD(_g5^?UT&z!@kPP}yY}cdMtafC$5B!3Z?G`uhmAC4=UF2__p#4_%dY_c_xN0!4 z-vtIcPLU#&sZykFyxNVsHQp#Ulj~2^y}h)_OJl(&&zKS1d`5-zMz>6yr)~VxlI$9d zo9}wu!R;reV~aCxul%a)leim~uAmf5Cg?rU)x&2e$XameY;&$Va`^3ua^_O|s%U+r zVK_M`z?S?8cHx7sp3J^guvfC)b+;xiYhY$uIxU4{@m;s;u9HxUH%cZ~ZIgHfvr_4* z+MxfW87qQK6Ed!6evh*u0B5eGFM&7Vn zqel?iS-xlWpqnC#bj&ya@pHPv?ikB$fS>UiT{biCxeVr`wcX z(Fpz_D`3~%g?a8QI1W>uKE>vK=P8`~Uu5pjZ_v5xp#~17GQpNpa=qOR#ggA|x!i5i z@$Lt7yz%=w-qKr`XT9t{NooTR>a?9d&~fL(I^M8F$D7@Fz>RmgamN!neYG2Jkg>E_ ztwa0RTTV^8Q`akk*QEqEyO;xRyvvO{o^*4Nagfi$lg}3K*Q2dUN-MBjcHe(EU5ZE# zk=7PhN2Jr64DKwJeTTCAO< zdO61wi6<9+=+dBD4q9a2(5mOOZayv7S^JExzNa;_&%5z%H{SVEozn4)jt73Fvu@7D zm&dqonJEW*+2EPec$DgPkk84S*1V|3HaFh-l78RxvX1xe((#5r>$vYPI^McZ$GiTn z^R8-6>CyMHI%&_c!Pif(jx@;*_b%CJI{u-t)^&`M@uq8ayv2>TyYU`3?)-vI?{VYx zZrpu~PTA4z#$VL&?ln4I|1}+Nyi>>hZv4EAW#i3erNGymp=Tq5|B_C*I~NjcID?mO z?w57E+X>t6R(aojs@b(DY2f4twmBWQv!1^@LynQ%zI2_m99`ei=v&=*-$s=NH-IiV zI+xX-ls&~7iQ0L;M&0Db1K-u}J-u#<8?S#*zxTQE`XA``u7`BI-i^0Btlv9+q~l&U zUi)MHzTpW?QV;gsacjrhaX9k}=?ZlG#Q9I_xO1nDcfO?KZM$^5=~XrB(`|BWTOM07 z7k&BQ$+z>Xo30UpZ8EoQ5?|)v#`|6!l{Y=JBH0}5)Go&!4cYiVZr-o!c=caK=~8%BX4EiD)(8J*PX}D%ECn@o5vJ)=1p+_8wc{_ z|Dxyf`ty79Ydb`$oZOkWHm|k5y1Sq~x+AZ?y1h5A-u>;)tM6A{pI2YoQd?UuR9)Sl zzd3K=>iqiN{9So_^ZN5T^H$5h&3S$Dt-Zamwz9f*on&G|UcJmG+AUxA7HrJhmcKQ> zuV8I{c4OY&{Hwe2*XM1|TQ{mJe@*`8{OU!C`o{Y9)}FjY{dv6wy`w58_ZCd8Z1hKs zQ!9H5I`gJhwoH1ypeL`swXktZVMqR&yh(+Hg?)wN$G4VMPVUNUZyYx`l$7kqySk(= zzdtXL=qgxLIeB7F{y2$l!&v#VX*6m4_`dwYlC1@6@-`QAkKR(S`>^%-T}Slf^%d;S zE0Uorzp+~uc7rTvXI^dLgb9o4YpXZNj92AXSGN>REZkABXkUI$!Pu^RDVs$r^Skn^ zWl{4ASLIhujz*`|?>JP-S_)uyerNvb!k+xDysN9PE-5PMEm&J1mt^w>^48|}t+r@_H$Rf*pmc3U?H4%C8K9GfxbHQ{*UalYG}FgpUVb11<)C8N3zz0C*Sp8Q~*j{$u9Y{1%>Mycv8ixU1U2TPIlf!i$Z+1>SP0 z@e|-(;Qt1yxDlSu$I?maAmP^dDOy_;7;(3!s>4Vf9o{N zFJ|%YIo)_C`1v!87cRE&XC~VG*Mo0*yM^xs{|wyKV)4&>hs7TgH~yforeAxx@y+11 z;77r`!G-U%_!AQre>!;4GUMyP8^D{v`@n}xGQTKg@hicTT8&qMuLeI1?g#%9yz2^! z|K2lgeq-8j)NcyzD8Kn-v@pW;T@|i{%^qTHyMwetn&+k$u}FHBdmT$r}5_a{`257-(~65f6l_Igf+db;L8!deYJ((2JZa4@$=xs z7mWW29`{A#Q~tx|Kk-Y(<&Haom1~Tz7S{A8f7$q6gm;5q0$1N=;b+PZS7?3h0WWqO z1S@+i{EOh~+l}u>{4rlMt}M3nHh7E@m9p21}-YG^!D6g;T7OX>x@4GZUz4e zycK+Esrj9ETKq-eKJa?*n7b_eAK(`71yjtQc(;XL0bU611^0jtJ;&k)_gMVd;NE+U zZvju(VEi<=7F;~l{BH22;QDV_{BMA_gMSGg_iYP*=egCBs%F_&i*_`fm#jo>jC+Wgl(Ve!uZ_kyPj>++0y%EGyP_r|*rKIui{ zg7@3}cJ4Gj89eac#_t91051UV24}$gz@Gw-f7$$RfZM@81Xusj!ncDby<+@#@MQ3b zAF%vYg3kv>!5;+ofg8c&cH8_`fH#1@0B(HM!tVob0Y3pQd(Fakf;+*5WtN`-@QL7s zf42Bj!Q200Tn{eXXPgF)`=@a?xF7tW}*6J>bM3=1yef?L4@;O~Q1 zzQ^JpJ_pMWK1*2Z->&yscnf&ig~s0mcY=QpUim%?KfBue0dNxB^L`7zS6It?>j#V< zcj0n;Io8m{Po}taP3@+{}6aB_^;r- z;PWrC{1?r$_#XoAtu77;}5s{vqRS2;X*@@k_#5AIchxFR3$b0Y4zD^|7$g!cVEU<)08S zelIxM4Bv4_usde_7{c3^7_&Tf#*JAXC6^ojH~dB5uP(6k*MeUJ7cRBM@ecCU#^Wxt{A|C*crm#6 zW5$O!Sa>U#>!n#3+X7jgx!gyTN!lzzu{7J_h!G)`guZdawo|}xhJOeiyb9v;;6@yC45;vWy51U?g73BC~A0-gt61#SYb1Gj&^6T5BxtPcypTpugJtKfHmZw2>&Ss(itAM0x?nCUP2qNT_B zyc&Er=GO=2{KkLD;$3y=5Yk%>ej2&gcq){^h?1Lz+Au6z}!CS!L0vsCBfyt9KPNzsRPS%1DNHr70mM4 z4rcjGlN&8{;PxH`bNk)~=K9|QX8Pl9GoST+BADxQDwzI4@FmFq)nIPVYrvd;ADH>w z0cLwr@)b*;%U1^G`mP1DJ!%AV`|bj>K5PPCj{I!_UjyC_X8qg^=JJf~vHY<8DF(AW zmJ2Jaxk}_Mc}VW_$i}1f;k&4{`bI_fu97ogLmot4wLgyeHK5sT>Qg2f-dlQ z@H+5h@Fs9Mcq@3Ju+DEMIDzo~$87#LfwzO#Y5c>3pg2F@E#G%FTzC@rNrX=Z??reC z_>iUMPX(VOto}6c8Q=@SCEzmfg~~?+K_z$&xElNsa4k3uUI_jqxDotWa69;`;4bie z;C0|f!F}MTzysiC!MnkQ3Cr)80xPdla4}f!J8;W04ZI9o2F`*j!Jh!vf>(nVg4cjs z!S{eyfqww*0{t(@|^%43!VfX5553g46X)G z0$&C$0k?uH!PkKs!Cl}EuwGZv{B?u-!9Cz@;7#D)gZscmN%IH5#o+DW^T0d7^T`u! z`6J-q?Z#>Fc<@Sa3HUSMO7Pdfjo|x)r3;xGei`DIgck>S!Jf=%O&UqJT0PZJRB6h> zR1oN?4zh+%luxwcKx{&n!l^e2UUpVjY#{}uRT`jbPx z&+7Af_jlow>DTKQ8T3z$jC@v~*T6p8gtqGW{_!4;_@%_gQ^j ze?P3%)*qSv24@fYKC92`^=HE;)1MIXeO8~>_h-W=zmeZ8@!#Pcue5=AymEtZG1AsQ zw}trb5I+>+Z6VhDM0JEAyuG|A@%`;*ukdi&3-4dJ{0b{?GMCq{pSr$$*77QuV;T4Z zd@}vj$e*(MKC93BCH?`QOn*(t_gVeMYKyQSZTTnD_v@#o@3Z;|_?N>c)7Lt$gR=TQ ztIzv8u7OXcf3>p*eV^4Ynrji>pRxRt>HGQB^nF%;Jp4NNWcsT@>HDmH4}5uK(Y2Rk z`W+$PXZ4F~EJ6xCnf}U<@3Z=A;a>xvOyAFMjZE}e{mJtzft%rz>HF!a@3ZvwERA6`rF~(51&lGJLLPUe!HBP)ZtP1Wcq%3ntz|wFP8I+ zI&6barthbxzR&9Gc}*RD3!hBiPj9&N8|%z}6+W51pWblk?}h(Q_+0KR-gB$JqVvne?rLjS$*EmHUOVY-%qbbCi<*C?|<6^ zpG@CRPko=&=lya=w%Ph8)A!RGE`8o#cQ$-7{l?Jp`>g5ne!MyG$@B+8zR&9O{=KE} z$@Km7H2*%U-zevub+{QmnZBQ%`aY}A`vdQSPo}@fW}mBnKC93B34aWqO#k_i@3Z=? zjTYg*;gjj(@>4E-pVi+KG5@dd$@DMOFEZ$#8X5VlKJRxNzuf8%S>sQX51RL!@3Z>6 zKl1nR$@Dv99y%y%`W*@~D67x=DWAF0(kE-Urr#kS9h8UjdH?0R+RZ1^uXOgH@3W@Q z`!(y}lj%^x==1Po`fV@_kmH_osgEYV*nTt3$re>hpfq)HUXl>Em>CZuxyypZC9hA3mAB ztQI#Y*T~3c^?ASS5g)Vk$@HTkpZso#ug6Qgels0B2G>*Sz>~l+a3#1M+ycHCyb639 zcpdmYa6fo6nAdN94(9cnm%zM!^LH?>-;DjZ<)7DY&H(fJ&3Ry6zo`QA`pqIRuivD= zynb^XnAdMU59alobzok<`97G}Z=MA6`pvJwyneGsxESk3|KxSZ@*FvMerqh4=eJG+ z^ZZr`nCG{2eIM+2bh^anx|gWIJmKMvM-y_MSBD>TSbZY1KJ9R!gYA*eS|548_5ge` zeSiDY`s}m%yubT|Yb|{;eSiB?-)HrCKX@H{GJSvhQQv3vTjV^d4xfcjrr&G9x$W6! z^?CpKJ@Co&{pHp4eOA9cVF|nppG@B`Z}ojvpZB{LU1#M-rthaWT>88}{v!Bf`hIz< z@3W@Q`{_RopG@B`Z}ojvUtYN7hNt0^>34_9-)HrC|Nd+6$@Jf7`5WcDnGRDwVdY1r z-*3UW_3yK$&*ufI;gjjVQTlwopc6iszF*#2em-mZd>-LZ_+n%99{64GC=O0dnPp1Dy%U>qvadh|)(+AV{`)`_mpEdn1#81E{({Hia=ko8f z`g`Hu0G~|XPj9&NE9E#?hi||qkJRsm|1f+q{WmJVUGRSnpFC2(ENl6H4L+H^U*C24 zeb(~h^Dd)4Y4wLp->Z~nkC_giJW{_$jw5uq5g5jl;Z#$ZiY{$ zzuAIw^~Y!R`8>~U@X7QShJ2sZFT@7g)>Yt0`A zpG+T{N3Q&RR=*4WS@6jt^~XrRL5JD!$@Cjt=-~4Etm(JFkHII?f1~}!CipAhlj&E6 z()U@@4`jcu!+*jj)33JRT>1H|zV=&m_!@jN{Wr@08u$;uC(~bNv(KgPv!>7I9e)C! zOn+s__gVdZOgL_p)ju-*4I$rW_4$0|+3?Bq->CiM^O#BaWcq%6tF?DqGUy-meO8~(tKI>htnnwxXQO;{pzpK#e7^M=_+7Po}T;Wcc~_S$#gAn}$!O zpEW&~f1lOo^SqyhPp0peca5g!%};$k|N9;IWcuy;MF#z&zR&9OdEr08Cu@9N|L7j% ze4o|l^TkKpjPn1SNHWmJ<4QT-XZ86!^1I=a>94oh<$Ryj@BF+)XogRwzdhvptUjN2 zz8yZ9{&M{kBtrtdGW`aY}A=c#`SpG<#(evv`{sPD7-Ww*NE;859a zv~H3$zOKJ={UU?@QQv3v`TX|D@W~oq{c8E>K;LKex30191@OuA7g=!5_gQ^DFTNB$ znSLVV`>Z~nFTV{wnSOo9_gVd2U$zL(!Y9*j4Ea8*&*#}+hEJyNr&l8reO8~(zn}Ff zTYqHw{{BvVpVc4#70cif_+Oo)%RI_z8~OO_+x`h35^Mexb={pHp4eO90EL--VYGX1Hc z^nF&J?@#zI_+ieud-!JiT_+`u_5&@3Z=RKgLb)$@Kl@Ro`dz z`96()_+9KHnemPU-h)|AVaYwf*#$SACz==le!3gHNXKFR%LKbrN5% z$MSiu?}Pa~*OOpA&-H6CpXb^G=JQ;KthV{_d9D+|e4guFU_Q@P2IlizbznZvwOILZ z>EGb_f-d1=DGv@kA-*@nKMe5`A^y3rUjHn{4Pq~Wd4Il^UsOjJ!uQ+mllV~v%HJcU zA3falO}_u-6B4fLm#nka_1l7ZDC_$1S=TS$7xOH9GW|&*-)HstewlZD!O|zwe_p@H zpno)dpVjC4Xu9B&HNNJ*M?N~x?{Q?TKHpz+CwwyfdN01F@3Z=R-_4KVlj*mHe4o|l z`*B`?Po^)MfE$!GeV^6m`*dD|Pp02!dT#lBR-fH_2;wZpYK1~1D{NPe5m|=R-f-nn)O91 zfAUCuzF(;uKAFD1y=eLStm*T8Opm}P(=Q9<-)Hst{-)RAlj&E6e4o|l`<_nzk}W@( zzTcnM{QImv-w!nnKAC=3D1D#R=li4{hfk*89`b!wzp~FFoGa%Ubo(LGZw&e5TP41` zUkcAN-wo#T%nyP2JoD3FKF|C+FrR1E^bWQ^+bi*-$cz3tL>dC!pS>1(-fCT+MY>YL zb$Q5Ko^ckOYfpUE^5}*CDfr}(`di`mz$cH?-vPfDK6#}6Uie$!lSk?oJsh~<1^DEV z`o-{f!zYi_p9;T7&fDnvBahUtgg*g3d8Ga#_w~N9yl@|IXX2{K)iogwpp})93r_8sU@a zUmfzvAD8&W2-81zhWO_p*7+T*ybqJ}W`22}C_G$w^L=|aNx0S*GV|+~Z;ed!S(i8a zL(BAI@X7Sc^otDoM}42w-?-TY2hYJLYy64w>9^pV@3Z=RKj3coWcrDa@3Z=RpWxv= zw*2Ig`h5T3+3?BqyY!0;`bU@FXH9>{V=g$T>Op-2YkXb)MHZa%eOA8=1=0kcOusVZ z`>g&d_^aTP>HGV8&A-p;^L>h6gHNWf%bib@aAC)*93T_{M|2lx>O-Z=cce2i3^H!{1WY9mFU!Qe(_x{KQ2iMbO0Lq$wpEdt0pRn*J;gjk6%RAiiuY&&q zeDX;BPWZdvlSk@z!T%?G@<{#F@W*}4wjc6H{ciXr@W~_f*TA0(pFC2(2mWR7$s_gG z!oM0mnZAF1K-a&|T7P=s-vXaJQhyu#@4zS1FVinF=pRj={Jg~1<5j*7>lNW*jfmkN zAs)SUX!zkF*7+Z7e>y?pM>%u(d#3Pk{YSnZ`4$P+{V7@JKT$q~n1}Lk+Y{fXycIr~ zzTe+e-)CJPl}}j$e}zw`zg54;pnuf&S$)2*dBWE%|74A?`ClU+9q9Y4KHu-0flsEt zS-*I`&+7Ai(2v6>(;r_j)c0BauAf=>tMJM6x9Arc^iPe9d{&?DpDy@@Ek9Y~>+a0SSA9BsGX2T=#q)hupYOL`0-sEO>>)#apVjC4upfj^rr%?FF8@BO&-Z6P z1D{O4Prt~Ze`;jpv-*7B_AdBjjql1&Wf|!2Hgv2$-_Jez4l92${UR^Erth=*e4qD3 z_~eoLeE;|R;gd(|^L^oq;FCw{k9o-!a5;Q3{jvH*2K}SU@3SsH-%tK|_+*W*<=-eD z9q2bYGFG4OGrtEunSQqyU(@$l{js|&!sGDC^l`Y6OW$Yp2jFjqPo}>il)lgEulj>U z_$z!e{mmiYXZ891_LJ6G{Ug)w4Ea90{QuD+OoKlFre7QKeO90Ei=PXhOusPX`>a0S zFMm0FGW`i5-)HqJU$F=`z$cH?=lko|!Y9*T6iVM`O`q?(|1Nwo{rZsav-*5L{uA)Y z^!@U#k%>O5AKh&U{GRy-)2|Mt@3Z=RAOAl1WcnLIzR&9O{rx9=)9N3Yej?=itUllO zKNUWCr2e!&Spv22$@ItQ7a81Vt_4#`QAA?UGsn6dp z_!4|F{T9iC4$7Lo&o2LaTyU^~`3KW4vf!NWv-;JD{~&xaeJukWlr?>y)o+FW6nrv$ ze|uNoXZ5r2e+{2Ze}{gNLI0@lv-t9@O@B#Q_jj#S#3(omItIyxJm=B+v z^Yx1i`bX0b?|*my)ddG>_+5G zeO7-X{0HEZ=@;r38T60(KC8d!?=Coa3O-rmyYkmBGUy-m!{yii4;LK#20od--(INi zv!>7AANdP>GX0G<`&{}ytKa`mi*V{)R)5L#Q9X0M&+7NN5IHXdpG?0nl)lgE^Y>7a z@X7T3_O?bQ`m8>GKcyc&nSNy`eV^6m@2&h1KAHaHkngkl{C$=~*IW6K=|@Ap&+7B{ zTs{b&JW`*(|8g6AGW}_x^nG^uFVL9slc{$j|6uz5_EsYkeO8~pFLOD3GW{J`;mYd! ztUiB_=I8Lq^gA?jGSKgEWUM}azh>$^mVa{2*Do^Ue2-oFZ?g$shtJ=?(Ww*lZ~HALoR7EsRXRHRSuOK7UWA3qF~CQONgMeg6K=+oWTqc_Y&wm#<4dxcok=&)@6$ z6nrxMV*TRzKC92)_qhW;nSPh)x$^f}ef}QM@%LH&$@H%d`97=9-w(PBKAC=X$oE(ccK}!~5mefcZZ9d%=7k{Ucz$kNz1j-$%a_%=gj% z4b1n^AMx!VD0U@lqj!Y(J;LueOt$|%EB~5M_~H;>72?l^_#47{KP%q{{=HE6;~IXX z9PiQseXe&zj4qWz{WE_KAFC49e>JtUiA~>kshB^!@aPOTQE8AO9W8 zKbd~7evv`{sPD6;UwN!Wco%%KPSyOcwcwoZv--P^vk32lPo}?J=AnbKroUZ524(g6 zdtn#BCu_K-@3&9t`>g(=@ftG-u7yvgKj1l7S|@bSKbpSJ>gRsn z3_e-oYyQjhiwycleV^6m@1gC6PuBSAXXT>SQk3D{(M%Szn8ZS zKAFDXKhgAkR-eDG_bPlc{Y|0teO8~p$9MF1ZT*o)>ht&eroboD->P3^&_9}gpEZ5{ z-d{C*vc{h%AOHA5eV^6m?*pdclj%>EdFY_5zR&9O_XIx$pG?2q*@M2%>ht#pe+HjS ze^JOM|4HI&e}}&>GfGyBGJjuYJea>PbGEYVKYOr0Js-^9OQ-_(Av^`9~ZwY+`S@+yaaB7E{l{e|$~1)n@p zKLNiIK6#{m2mB`Z-ousuX82!%Padg10DmKV z@<{z%@VCMzkJJy|sWF4#CHUl#`s3h_{+`ue@<{zj@K1tI9;tsJ{1W)&k@~gpXTv9t z)Q`fy6h3*Remnd&_~eoJ2Wx*iWqyA9^F`s|`uqHS*F(N<>yOOzOG4X^&$|8a_h4(_ zlj%zn>;`4setcHH56gcid@}uAA>U{9`TMhd@X7SognXaXuRK#@2Ep;Yw)|xJZ?yd{ zg8y##9>dS@3ZEAC;Sh?C)4i^`97=PahArEel>hDegFOQH8Rm>_4#|h zH^3*;_s^%R@3Z;?@79<>@Ctk~{mr5KOMF&;%{k`hKWOWZOn;i2`(S^=XZ5$iKLtLS z{?#`7Tz|)B^=r?y2vgyc>9>T^_gVc-@aMoM)9(xUKC9n;p2iGuXUk=%kQ)L z{C(yOd@}u&A>U{9`FqZ{!6(!A)2oq*KC92)e|`);nSNs^eV^6m??wLxKAC=3$oE-& z{=W3z;gjhXg?yjY=kHOU_5-VbWcu|X-)Hst`_(tXC)4-)=QT3XXZ87e*Z0CF)1Mql z-)Hst``AB*Pp01<@_kmHzo&ibL$>^6`s+i!&+7B{w=aiJrtjC68ky*``rF>4F=aml zpG<#ID1Gv?5?_xG`1_JCgZcZCe+TpTC6Da0`22mz)4}|G$#cQ{eaT8Ne_!&$VE(>j z63pM1yjHk47#wa4@fSk;)ezqq;@%Kzc^s_2utnlWB@Tz5^&Q}N<-Jzk(;v3=T>{pr z6Xhe#xEqvpefg~Gi@&G7;9>L08ejctXAiblKC92)U;i9@GJSvh()4{+pTF0>4L+Iv z)KL09tKWB_#+2*nk68Z6^f!lmpVjB@!@mPQnZBRj;quSllV1v-OyA!=)%RJ`uYJG9 zl-GX1C)4-0FZF#^pTA%KID9gFe|@R%v--P`e$fxH{=xLeh04!o^@9)SCN9woC)R;kV2YfR9eWCPy*7T$0=5K{h zrtjC+8ky*``g`F24L+HEe<*#Q)$gs)m{PAFwelm=_sd(;_gVe1v&>%zpG?2kf&=}d zzR&7!nQale;gfahMENwzM+ar~8x>?wR)2D(ev|Vh@X0z=eZPOEzR&7s;lJmRL1DL;`{X^kmq@{nJ3bE$rVEvunOZ=$kzb-u7`Prg5 zI;S9r_uKN4xxC{r4`nScpS8S-;a>xvOus1P`>g(C_@9AKrk@D;KC9mi|33I+`ddQ2 z&+133HD(Yz2A@p7!-WpkH=ott0smL<$@KmF*2qMk)vukaF=hTgvhvTdOw;YHUIS&& zSnB(%{#y8D@W~o~B>rCbAB9h*@3-%ozR#L|t4@?*6MQoLH7;~8|30fg)nT8r>^<{wPIC6vC;>Nj3w{>eYK@+Z@;4*5Q-zaIVq_~eoLd*LVGlj&E6 z()U@@FPpD1<@a^qlj%bZ1mwzh!yWo@Qj|=%e zt6vHKVff^c`itN{4WB$xzZL#Y_+QA-cobR*x`xaV+^Wc-|`{k|a`>g)h51C&DpG?0@@}PsV`eh0- zD63x!e+hiDhHL)){;m2xtG^xoRq)C5{q|aYpVhzmQjHk|KY>rC@259h`b8f$|F`hT z^e4Ny4=%sYn*KES|A0@X-xKnER(}BgaZg(PA=9tSw;3pF{(V-z_%aQV?G!#)r)v3+ z*FYJR)%RKbY4E4RC)3Y5d(ih;{q^wY!za`C>zk(Uv-*ATo8gm3>TiReg-@oxFqD6v zHT}sA8Z!uPf={OJ=XbdLm%;xMd@}t>q4a&$^jqK`@|3NA@<{zI_;L7T`V&Iw`>g4& zhkq4(GJU_iboqT&zpznb%6UKdWcvM~^nF%;3;b8%lj+xne4o{y5Yd=YKet->UUr#{2usZ`WMPPbWqmxeOA90{v7yZ`Yp~L z^nF%;VoYPo&lbZc)0f?v8<|nrP$n^c^J=FJE{f-v%&w@{;zux6;u>5>he{$UX3*nRL_lA6*)!zxf20od7 zWytqg{gTTyrkuBcPo_UPHDmH;Zltm z1fPOWreEzs2g~1Q^=sk3_otRVnSNQw_gVce_@9SQre7cOeO7-5{Ny%EpG?0$=m{pvI3lj-~E)yPDj)en}L|7G}O`i(ks8I;v;RFFYg{YLn&z$a_CwqL8|ql2>g zKC8b6e#_4+|77}I1y0ZTKC8d-3XLhhj|iVkztM#brth=*JK%rt=O}+L{hpBTvr9j1 z=^sB}{z@=?zr1T?qR;9NApYOrlj&~^rB6QjSv!6!`-;Yt`~AVS;2GdX@B(lbxCOik z{88{0@PC50gKt+pOxl}1OYb|v#V%zVJ*44BN;r-WpCeDS4&+PV;O)kL1CIymTn~0U zdH64e9#5VuJly%b&Wz=+Q^NIllB`p;K9*Q^bM?t*T_3&hAB9h*KPlwKA1-rrcltoaLWPe~|^}^6#^z-_m9gqVUP|cZKrrv-g&R_&38R z(=W8y=ko8f`g^am2Gy@w_gVc-_yMQU&s+JC=}!pxKC8bCeldJ9{c$1RXZ3f& ze-C`}Nd0~A>*15>Yn|3X|J2CHXHCEODvJ<>Pu8hg|5wRJ2W9nrR(~D*74XUQi<~{^ z`>g&(_-o;l=@;u48T5~)@3Z>bK57xZ1D~u@HUE9`(Lq`LJ_Q++)n9$Jev|WA@X0z= zeSdwa@3Z>r;QxZl52im&zsR6})c0Ba?bld@xBb%A4OypZ`epLbL0SDW1sRmpFaDT* zlYSL^vQAaMRs&^FR^Mm!Tj3YHVCj?TuXgsJ@3Z=aAJ>>ckcLmDUm5a!R=*m4H+(Yv z$sylo_1ocp8$OwSf5`V){jv^?DZfYmD_edt{rZsav-+#yKM9{qe^to$S^WvuYE0>u zZMXEv^vhl7VEOy3ek1(d@X7T3{MN`spVi+8|B+u?`egc@q4deWk@$K(csKU6cVSnIui68aSzfX9$`=86M zv-}tT7WDzFQzy!&%Yp;_qvh$dmgm+_ScK2OC+k%8qxmwDL0NsD)t`F3hRE;#?y&U9 zI#vBKA>U{9FI;8*U*VJK`{@mre$P$j|LJ#@KAFDXeyQ)Xray4A`Q^VipG?0}7fuFc z^?g>qxKl%d;Bxq6ovO?4Z~y9(KPmCGK2Gj2{}ymL_?zHGV2u^EsPawTCm^3Ag?Yd8 zv0y&0c_x_84{E+OKA%U6fP4Goiws%$X!x2>ICRg&Df9iEYY^U8ZQ=KU`F_pKU_S3B zhZ}Bwe17j0FrUX9E%Vm-^LYh*Y*U%%$Ib@xdV$_HqTxLM{}C|HXX#;ku z^@`PCo0sV} zxB$%Obz@-mkC%h_`|_*6{Jr)yV7@PQJ(%x%dmPO3zt4l&fBQ3-{lT$vT&l~%>z(fe z^Znr$f_eYoMPNR!+XQC+JPYRU!`}er{pPoU`F^PTzv7!6Tb$YEY~S@ zI7YTD&HqBI-?PBHKm9^5@4vek%=_V5z?Bc%{My0n@7)NVitsOji^1Ok^L;h_U_Ouf zJecp3{3Dp}rx`WM^3V70jsx@h$7C>{51#?%`RO`v$sEgn6wK%2J`U#dZeIlR`L%C? z`M#%zz=JS(xffu1ZJp$(QRnLO?yw)Btf4}pPF_vFmFB%W#@!}M4 zH_E#bybBx!m+i6gxB|@Q6IX)yyyh)nKEJa8%-EHIDXF9!2?d?~mH_4gVuk5{|E6Mt;^ z?E&-t>U+VwKld>(-v|F2Fz-M96PWh{k1Dd|;r+$OgIkfGv%q}6_%txz_dOTP_rFKL ze4l?ixCr_GPcYxNe>a%V<2?%I^K~zPdH(4&a3|K^VTW7(+Y?qklfk_HR0-Z&XW>oY zMBMmlFz>fp1Lp5TZvZ!@EPg+j_tXCl%;&NG2Ili^M;u}Kjm?9x2M64D39&n4QT)W2wq!b^Vy)YJ;twr`96*@ zV=cdY-t-jkx~nYyx!}&LjcdT!j~OokkH6OV8t@jhSDy!uL3{OWaPSF>-w*DB|2uFC z;{OG_>SBvO<|xZAf6wD&Fz;tN2h97E%E5*0=6@K>^JUAx*`$U4Cz#hq*Ms*hKz_k3 zOO1Dcc|YgqqfwvrKu3lN;Ib=>&jYtM8qWsv{r=71&JGK21J`4J&sJ_YhA zl#lk&M$6|A`HYdzq4If~e2V0AxO|R~&yn&OE1#p}bF_Spk1d$miYiDUna9e5T0f9Qm9p zpY!B%zI?QAc!7N0BcJ!m=R*0sPd@LL&j;jFCZFl@nIWH<@+p^3g?whoXSRGQLix#SX=p1QI=H7lJ;W-aQ>$g)^EQkhCEB_}UQ$Fs5WNH#J*wipvzV$Dl6YhFA~ z8qDoXe^OmGl8wPm#3JeGi3FDo3p`UN&zf6Tk<6x7Af_$djM$QRa_E${Y&MmwO~*2n z5z|edACp;Sn3{!Du#iwInzy=m548C$yTRQtw_{Otx9IH zk-@yVX>%j3)sYo3taG!qjD4>*ooeC&ImxPkAH}9rv}0OZI+IEdmR5PJscp&ZSaxPx zIvwLO)JUbV=q^~wQ7RWFESVcwl8j~J&Go7B*pm8mTP~^tH5Q3-Xzkd-G~pN=FmiMD20+2xV+(itgKjEbZd)-0*D z(yG|}Z4x(Yf0|!-70EVjVzP9RcExf@VXy!y+Oz3Mb9Po-R!A~h8_BlV{ANj$#S$2- z+&Xp0wxbh`_)<;0AW{Fel;!BcV ziRi2?Na|EoZFnx3p-WJ=Vp&rP>uPo^=?V$Wwyic4m27_6d`bnB7Jh~_F44^FM5-y0 zQ}+v=S7%9wH{7b^;?!WsisnSjuOAW{WvGQUn7B@C%4tg2sX)M90u&z-bNSG~S>oRn!zNP`&NZ*~=lNNXk*t&g+WlGuzi zq)5CPlUs^el7(_HlNrhBU`A%w)@hr9CCJ4dI(e|tNs6{d7?NIfB)Oz5vIG@V;;>=7 zIFgRLqRGv8ZmKO4t4=i^WNN5V%w17cp3|*b4@ta6dI)}Pm*i`*ExC;?6=geO0hay2 z8D?Ajtz6@{rpEd-^{GnfrX&Uz%;L_BBoa-L=B2VGq~#neObZ>7J835uX9hPqnSWh# zIu=U~TmLPnE`HTuf^{o0(vKQ418iHlMUbX$@#1(h+TCIDaB(a>bfsS$PiNaA3E8pB zx^GU$TebG)=4U&X*|F5JSguPW`5rpi+cbv;Ts%KCqpHls@l0GA-OzODmPwXvVr3*V zq)8T*%r&JV>FBIfa~n#yN?MM1Bq7CP3%TE9Y|q@)*2S{5sf;*GrYd9opcye)Z78oq zj8+D%#_UuoHwn42T|{oGB_En-#ZaaDGxkbl8C+*?aQ{%9ins<|cM!JdI>q*8VV<5@ zk!9hvU> zUzfxai5anS>4aukBoZWj58cyRHiYXWBeA&>1^qRdv>@3!B$9MuW#8)Wkad4CSO!Yk z-5yeYu3ea!h&L}Cj93$kMKk+%S=?mZ=MU+%xT#zgFBFwTw&&*9f=nzuUAw-mQVO<6 z-t?iZlIwKU$I|IYJh|{gms;%kQgBv;+;D84}xe!@c&XO6i1P42t!-xB=9p@&svMw24yqK$y)1~lS{gKUOa2?E-O(mYy zg3Gujk;%J56>B7OlcXjO*)ZjRMkdusA1ua0qxrFAspV3C{KLb#$Z~g_Hn>gHNvAT} zCf&5qL4>rAsYK!u=`1D&b6Dq&H!~U8|J0`}ean$-{?nVY@#Qh@3)}(CU>J^o<__*5 z#PB)^AZ$$_^aDWX27uT}AbO#LyIAh9bNP_|d+RX!dznc^I-N=nU9U2gGZ@^>coVB5 za?FKBRVU{Pkh7_hj!1er`&<%bb~@79B8LRtk*-X&dLy;9X-LmNLb&b*51wSAs~;@p z+>#C5F&tnrcO){Gq4BvR84O5AmdCR=#?DO*?Ot-zxq(U}p=&sly1(2^;^dJ$Wo0G z-qS5e>Xzg078WGa2Wn$%)`Jm-YhwmO_itsqu>IPZ!La?SQaD||tr_&ft<8dDW@zy( zXpKraxu!(x)R4m_>{ByUN!A8VsZGg=rs%vjG~;g1SfA1+Tn;B1E}e2-gF8cYv2+)7 z_Vq1t+8|mNSscr*sGZYXSJEIG=ge8TQ!X=S*;=t3s5?c))x;p#dCpjo)#C|oN_8x` zM33=i&RQ_PdSvU;icxhW=>u9oQ8(d(kV@m zOuV@vRHuXQ6bYVkgllqrsX(ICRCi?oLZ*Gsg4Gl|l%{Q%(BGcjDF18C=+cGUuSDKera5caAa+_INF@H|oxefnz zt|E2&&8Rgo((Ot&wa^w>-%wxDP+!_mA#0)TyavhS1um0y*$ZSBD+h+s?6?i6zA9YJ zby?~!t|^tRuDQKE(iC4_T6(^GPed}AhOC^lXo$-hj*4NT>4ut#A0Xy%$wU*iE)&Ts zb-gx70;rF}JO(zDqO($X|bb7zyJtxYtv zC1dTa(yZt)gH2v6$G7{>tyPW*8kXCECu6!MN5QoV`ejLbdqb=AHB(7xxU(x7mY3*M zIceOyw4u3WX~W`3T-$eVikx^zyQH(JHrZOGPaSD;y?d>HdNNL0)uyXrX*prkoJh&( zlek2QCL+MP)RhC zO0;ET4Ow?~#!b_&uBp|vsqs{mzp-V_%jC4U{%w`+jQrJ3anPV?xa_sciRi5KG+U*B zWVh9@B$mxc8OP-)e{kZ`*op=@l_0fja9Spo@U)Dt>5SaW<%{Jb!(^m*Wiez&bNvf7ID8$ipcx-QcA+zl%Yi=nRKa22g9YB zl>T~E-At(?6%`3B8(pQy?|IgRsj8jg%Gh~{>e@?yiy>MJ&1?SeCe>5=S zj#Nc+Li=IT@L6{W+jaE;4nYodq#)hG!65Bj{-3W^Q>5f$%j8r~b4)r-@hhYq)m?Zb zy+rm6=Qn(C{v55A*e^&my+Es?uCpq)$JoD3euEX)Wb3ZHb)NK7{TB59dWF?SLF;To z>|Jv@Tw5izYKoL-ZqM4_S~r=!oHDRR?;@*d6y66X+$r~^J!R!$h!NF!RqGE7|Z*u1N&6dCc{5M|s z1BfGB?gQ8(T4c9@+1c&TQV+?s9oh0M`0Td$3^~mai`Lo(I-IZdyt>pKNK@l6;K8Mu z;Wmx~XY=1&%F@!gauNhLbsl^pIdC3E+&Ua&7W-}GR^+%$XBVvpPZ<1bWmI~BYrW>j zmdiP=*pRm59Cu)aRB+BhZXU3UO5t-D)l;U*IiZGSdNWN!Ybw*QIF)X=Qu<7(D-Ti= zYU6dKdfh|LkGS(ENNnh(cR9|)LGd~6NHdh9R0cPIhO;!q)iA^kU!upsRMAPIj4fD~tK??^k3_t8v^ZS5o!-q&FWNHCsi;EZp)+9Cyp3 z9g$D*3xB`c4(z~t%6W46F?aW5IQLUZc7#*pm$WnG@~qhZFm<Rd+8$f2Kfn-(4CNkCIo&v1!+x-S%}9#mVE!8v%fVDTulcVP%|Ykq0{`{m zIY9SkBqehI^$iN;0M?r+j|0u>O%{c#ingJ0YePe}Uuo=DYY*&No&48V%z@|l1_gXz zaRg=TijEtY9n}rr?7eZ34DY?!;uwBzZ%`D&OK(^VrKNH%N3NR537uqfZL^-_JHYK7 zBfN5AU4nD!>Z_&mgu7M_GS}fQ$N0zVdecb7<=Wzvp2OMIr)2K6bM*2wC&^L%0kS=1 zxD=)wAPLu_lq(YD)z$K3fo>VGwC%K9P0NMo9lUx5O!`~a-6(b2r@MQ$TC(QO83@jdYho7yadW zgiPE23RmfV3tS_oxT|n+&+Slf1`^k=+)1Q2bpqX8LUb1sE4&*m+$nXp8r|-Hx?bX~ zudZ`_HM<-sg)0->-5oYTF5Tz^^yggtmNK5va=q#rFi)Ofz z*{@(OPh9S9(X!PyFChm33+iW0`#0xmHCRs?>CEa=GT*mgj;Qsl5G_N`b+zD3*D$Mh zn3#GYNiIgYyS3!*q+z7Dq)zCaZ<#CQ!dI#-+t4icxXNvaX`IHZkRoZ&E51X{?MYpl z?=BB{S=ukso6no1Dc8KM!rFPkX+zGnhO_h5q?GH{4&ChHGI#H6Wn9)^=rk(Vb?8!Z z)Q`DeC%San5;+`ibx%g>9UyWOX{Mrf)^fSmP>;E5=S1}y_Rv$I3+k&8^*@?h<#v$$ zFL9Ti+uoX3re|>7LzC`a0x$DJuWs8JQ$G3-I!$2*bPSZkGJOaxcM@Z0Xy}k(Xr^@o z<818gtzCzg2R5d=TZ`;@nY1+=?v%hRxn;+~v^D3wm-{Vk=@dJVv2N1P)g(pe6~CRl z&?a8)71dqB^ybCpYCEn4SzUULPM;OQxr%>x|0r9B?LyrC%S##ewhv9+)`S;pXmF@a zdE@0C+RB%@jR#9OFNqUG|Lzjn2^u>~XnRy-+O5dy(sOY~GSjnOh${{Y$*lt?SdEe$ zjGh6|vl?=S(rp}`C!zAZhwOd55c9Mf5b~@(vHReAUQM$Z>GPzy?!c5O?$O@;9{Y7x zP3g3{TuSVwOB3ZXIecL0K>~A4&TzA3D^u!r&$78x=pD9}dDoB8#~9o+)ZtQh+9)?w z9&KPh#_g%AQ%h`dFNvg+(%itZtu4lj7uhW8q+;3913&ugf?^5fwiGwmdC10 zZsmKcSI?qpZvlM=%Ys`bdn^QL@U|@rXW`(nD+cLzSKj;zJ}Ab{@d?A8*l}qV6Wqx*0?Ee{%DJcUyMV8@C6!dWJ6f zdFWKgDPY_hKD6~5I!9?pd4Efl>_Oy$Q3 zbGyz^eaaqnuMN+|_IKfqqDxAy87|YyBKsxfielKV;$X6t9CvUBNY;+a^;v6OEc6|) zW7cQk`2b+8Jge*W_tt5%jz0t4OLP+PT8rRvJ~V>$HSBI}yX95Y(6PsXS7)d!-l$&e zzf#?@4ZBXIirHOwda9>N4&vmd9CxTC2aBQVr+0K8==f2hzR43L{w@>GL!IN5|M1Vt z#cP{w!#&6KCatigBR$;P46J%tSJ6Fpx8DJw>kj_E_PztGsibR|-kXYILn2sEDG41F zkSdX?6a`BN5HPf05)doJirB@qBZ@9IY=8xIZHRrX*gIHIQ2`s)f996tCN}{@*M0Z< z>2qf0%$ZY>Eb$ew!f9}cUI#o7G7jezN_g2zg{=4rBA`Xt1tNN)I70f-RYFnQ zFKLR*$RTep1a`b8^qUZ7B(S(fOz-ixha_32bU~Dq+AR`aHr2f-BU}O(zp2VCmVh?d z2uThq5empw1W>@O)|&z&rdN-{Okf8A?;dndgDgbykE{qmg@E{a0%g#Xg?EWPyIM26 z7DK9;X_9r5tPy587^?>dnT&{M2gvooSiZ<>OjwLCXUH{=0Zv6Ql!BlGVL_k{AmaN8 zDUB9Ii6>BUJ<^sUZ3)Tseo7!Kgb225&Fo4k zLul@ZVQesx1qP-+*HET9zoG%IKjD!ST4`!vK@6zAVbvQKkh zAa51IzJ+3ZxM3OW#N=i-E%J(#%tVu7vnO$r!o4rHNzvob#MIfq;t4q)U=QO{h9Y#t z4yvgsJ3rF>KJHL4bEK;*x}cT5Hh}=p;%pO>0Sun1>SpRx8}%3o#lK+G{rlT*Asj zUO!?t#6^5_{h+1LzkVRZfeWyQG|>KAhqeXFc1oGBJob{0?FcIs2?BF8w6vWjiRYv0Jfdp}mo`6!q zc~1zSB@tl6MgcJfdqM4a*}%LGQiFn~QThl|A0ScqD3keD_KQ$F821b98+9%Q2p%YB zfRYEkJ>qcE-OUr2`(x&D(uy`MEXB8IGhlAw<^@IuE!_0552@?Y0-D2KNNf@44ydpM z4dw-+Qc0v1u+f%6cQiBc=J5fWd@~{-k&FtO>8`2knhh>%xa9>~75qWIs+$;2bGLLe zWBXYY0{00dXI!CM2O^df2xywa5AIfUIA?H=jt8C)ksFjAh^kh32E)za$UV*R?**|!ses;+P zB&;_h$Q!OX`PRVjDt>3s9Dp`4;IA-J_%RFz2A>1GMf|M76p&X?8Fb*?2grzkn;qow z4c+Y!mq|?i16=`$stzL+iBA&Pf*nfV(*v5H&u;S&qnZ=Qf0L}hdI7&^Ec$cF>tC-?&gJ@h~yFi7x11OLIp zCjw}&&H&O5(g58;Xh4-!0BA(-8g+RHE>=Woop9QJ63}oGU~L?K1Ehu6!LxZt!yN!e z=7A}aldxRt=1q3^H`v`BbJ)fJF7gvtHge)A_M{XVDaC=5;z&xNQOQZsI7hlUtGiEb^diB$OhLz?NLf zmb{bf$xyZ@57deb1}pLmt;svdn%tu`M2^8hC_kR4<%p#t>I8T?nkJ3Zhq*x8I382U zgf4o43tZ^GQcCMUgAwuFfvIRBW$9ANhLX#|zJSRw>?auFBDAljMi-2E3n9N~KwZQm zA>ikyB7PEMF-2gYlnP_iplUd<2VZO3SZETCn(P4q1PkbwMtcCS&WKNXs8j3)eP+f2 z(;-604g@r@M0I3PBw#%7cMg6dIsk|-Y4G94Oha`7z~3MY0op$jdjJna;E@76nt+EG zC?GmYFJL(a69GiHOspnwuLhEYuI#`E6yM?!aIiwL1os*66SpfT7C~nVb5WCNWMTa! zSU2zpwhb&EgB{I7=^Ro~E2>ygNV-ZbY%f+gkqsQY^MIol5E=$_fEeh*(FGxHEir{> z)G`UCVqW4=ePWP+s0M@I!+_%`;K2>*oTGus0K{PvP>~CeL7)T>P$QCY*fCk=J^w%tn90DJ=v8G-txl9$`#k50Dmm>y+lD7Cm?p0yok{L-Rl!`k(e@ z3nvPVoX~3|7+#U+ImZ%#9tbP~?WaHy>ckhBoiKa^+z5!ihma5gBgQ<` zkg~w=K^CH8L&^iyWIlaC+z8~113(FU`a+0{gzNz7lBmiAMgvI^UPxyz{vs5Huxz9# zQOKP9Vj^9f%M2YGlSK+J5%AAtPJZDgho}lVOo!XE^{%6vlC=QFsdQhiGAF-4jMIdZ zQkj!q5Dh}+jWN98mBitIp?-6-I5 zwT=&l+_-=nmB5_vyO=DH`31YfxGaL_3xRElylhbp32v-_nqZ(DZ9>T(wJeahH+q#n8+}`DR|aNf*E3-AztA};nq|m&BLy#+D*ex zeB20!@rS1=9gu)IFNnb^1%8O)3W16Lqo9*gzj>%hsn|5YT0bE&kicUcxQqosvPC0d zBS{kDW&^%>E5phozJPsO9F80j6tIMhdx<*&F_uBg-~t6~?L=UYT0x-Y=)9JB@`h)T zI0ihtFbv_&DX*Mm!U6O$ziN*rh-k(1fhXx!UND+1{!2W0w5ReN) zwll(iqyKo+XyGT~xJi0MNPGQ|ER-dzkhHqZ*cD5w)*3T+scj*{ZN{~Lgef6O;%^g- zxNHeXnyTLnSemNZ8qhS^9+LUv;F0ojX$fScRBZ+*QfjpZ9@3g>B`BoRMkHt;MR9%y zbj~2XE_y_Nd|{-w*bIQBS8M@{5zyfiLm4@e(Qfk~kzB8};E>!}GoX-MscA5XGhVI9 znyCN7`o2(^uElzp1m+xI*0fstv3c!0cmo6fvd}V-X941T|2F<5u}?%XNETZFwFE)K z7a%TW0BIzPEzo)m3xex8QCEU?MB}<&tMvtR5)m>9F!5v|3ot9?)n#iBQ93%rxfigAV^)iWZ^uq7mg1BtdlsJB%28W^8!TCoM?vwN9zr2 zQhwJ$BYk0b4|-%~GZWYov5+4a3JDsU!UthrlTh0SED>>J3h@;X^guBOwyMO~sb~^X z5N9Y6OOn%&qPXD{p>3>74~~R9v=iLI3K}Xw2;v1r{F35B#52X6jAB(`#9PE9PdHd0 zdKLsIMN0vz5G)=k`YjfK6ixI@1xQ@j3Ti4N{DyW+!Y{<1wP+Ijg5J2%qkv6KvU6s% zL&(TYNdzI&0};EUU=Hd^78^3^M^M-!D2*;DE<+AR!wSJ&+3J`(kWhjvfQRoyZRvuT zF)Tg^RRm+8u}LQb*i?&~JvM2W2iq68O#jF4FhXyVkfEsic+m?Dal<9>$b(Vd_?6bg z<=1@tp`W7SrCG;7Wc2TaHG*(PcRFrlgKu3t7j+kjBA{9g(+kl3MN<4$V&os z1|*o1Xr82~Ot5{hY5XS8J@ES`1&_RiUEuI~!lOx}WrVxJZ2}DCgzPYc%?4=!(cn(7 z17i6gc5D(8zQzPQ2A!916N!X@LZ*v2J{C#F13&@Su;^MOMf(9SxXf4<9>fBvh>)g0 z*F{3uC|FIHgEm9Q3kr51EQNkxO`rumlTx6~J)ec80!ZO!?EhLAs#a6kxIZcJkWnqT zdGW~OC`X7Ui(@4WlquN-uPlxg;-?9C6o49=;HE+xK_L#Q(2!iRI99SaRvd0L8tjEA zvcSpu=CM*Mc**~@I9B4k4>F6G>}-MT=!ooysI^8sNsEAPEGsHrw48t)2TKy9 zKqw6_EDNZ0jQ1>zW+yr{5ocZ~j~ivn;f?&pFn2#sgNsL86JKocC~Js&dngZ11f(a} zgk+XE1Oq(6;&%p(jQ%BgN3=n9_CMib3NE8RGnE~Sc<%aL40%G2LSBd$o6F;a99K5B zwc%45$RdeJ5UCK#1;jwFFX*O+SYm z!>k=y(OBLDVGfY(u)*6LNFhb@0H;GrEtn&%7U&CaMmQ=^p~*yFCf^q~TtSc)URp59 z!GS@9E``7X-HB!)GHH~f{<}5-)|;fO2HY%CLmZ0TI=?A+Bs?czIS~J6__aj1(psl! zB8^84I|I;(V!`fQ`JlgK5U?0sR6;tGt)s3EVFhFh3x@`i;6~?<#nYfQ6eg8-jT)E2 z<^l;A>e!ETGXog6Zbsl?37x(pi$Yd?f@8uQy5U{JBmh^}C_eBMiH{U>@`vZKxlvqZ z44*K5Of>3B_u`;pAQU!GoQAi7rVL}TfxHh{HKa$lWdF@5puZ{1_piS^n>x$l7wP|% zaHZncJo#zX+D9JQ=L3!WqLbuvnfw+7TFfo*vf5H_pzyE)q4V#$JYZKC>43cnFkhqy zQkG-`gQ&6NVsTsyA<3dxq8(#XwM9*Jp%_Mj%6wA|2vyc06!G`S&rGPr22@QAOOhEC z?!o{75`jA)e^6n&lxa5;p;F9j4YcZ+2E3$V1Q^8UAc+n<*+MZ~&{!4=+=B3>jW>(9 zpCv@0Mc{|l@?}Qi*BxjBxHFAoMPYX+_zp=*7E1{NI%^;*H;Ai+ULBwiyg$LkJJuWc z07X3B0%0xQGor_VbWc>`K!Wd~QYBDd7UY&Iu74s6a?9dzQn*npS&&-{5Io?p3~0=N zcqAz5CfQNpCl1FqVz|3G>ml*Gn0ygRx-Q8#wxkdR;9cIl6Ksf+0Q$kA)BdgtlF*~@ ziR}rTPxDyOKnF@FPBzXM{-FLD(X=mH(|6#RM8cI6&lV zp%UVsAn_#;Hj*LMLR&!L0P!_O2$CN+jg&kJAz=kK8VR#VuJmKJfRfy)*#Wd5oEgGC z_9gpqhwCI7nD4i!`3bv}#Cegbum?vQ#7;~}0D2s_swj5yK?LY{qSijfpN77SfIFRd z4Ao$%Xb1pA(-cD|C^s8T$G8K?@j*;^JtRb!hC@O1Td)XKXhVQn3uSZpDa-`WGa#a) zxa?#hdj#YLO#smh5^)ure?+?w4h{4KrWeCQJHk>xzzaZra<~%+oN}1una1ZbqxfFz z1ePmM9z)cF#H&D;^+3rMBZ`Fz%tAJ4D2q!lhX4ccWhTX@0R0{mGKjJpzCyU6m}q=% z*eB$m22Dte%3LfV7oNs3nux8Sdi*Nsn4M0A4hNLDNxc>e(y0>zJlfRVp$ z5Q0eAa2!~-o=}2=Yky*CqDuWB6FCD|rbviyLPG%{(j9h`U;qvlRvb;jFLNvreUX3{ zj_7QEAm%9=3=%SR5|BXZQ1&4`9=piIg`@y^G?+JRO#Ktj2Riq_)i@jIdcyfab!g~c z7#zPQQqE%05iT%;fka_s@PVL(F7ar>9RZ3GY@D#zf=zgV zmPIK~Oa^}9=}p4nmxXwgMJb2Aeu1I@675}DXl~SyK~fY{3>&m0rZ`PJkT%k)v{2eD zX|ee*x1b9NUg?D);0f4X7NwlUrxT(6%aK6+#N~XE2M)WwMh-goO(!aSS5jl(_iY0M~>?a0!w0K>!2k zA(TD_=H5t9W0)Wo#9k0g9u672+5DKXNg%dPR49|nCdl5&UTS}aKM`1NpfP{e`9fI~>}kfa1ajEi=`iBCxu6at$!7JnE^H9U1(p#U4)6!fRy^nqn@rq*08~i8ok$Sv z#3z{HksJ_A712}2D7I$C_Ok>w90eEwDWJ3fIW&tw-K~&U7L5U-Lo$<*SmN|R5ZoTN z8w^9-JF=3XZ5o3e(~`L5U?g}5avqmv$L2AB=#JS!HL1(*q-Z!C;COt*nAKTiS;+49**cYGr~t`%G|K@X`A0zx~Lmb@$N z;S2@)(KnI?W`imv*+Z!Q?2=@9L)QP75S$o-*Dd+$NPk?O;VEBFwUn1oX$T^lMp*ZXcFL#1n~#MNa4pY92k5KgJw6( z=cjnLosT290q=*qpEhJ9ZM#*aI&N zESCZF37Bq79;+pXH<)mCtsNMQ1a>5VIRl%2EQ`+r&sSDj6br;J!4EJ!$Wc%WY;N$H zLC^&~hMt(5Kt?TyjTfA;JA)qR0|p7Iga6>XMF0&>34pYNG(fiy8W^BKI70kk0f^oEG>S|Hs1rApMpTH$9g>6{r3I6(1pBq^L9TA3$anH(453L zGk#s^l;Xd(e?Hnlh*G)boNg1A0k{OU;J% zA-QSO?pS($n(}PE{*$2}lH5F|tW;Zju-N06|_~>vUgVKIww}!i=#X~HEK51yYKU~NQT=~bh z`YXPlCUfR2DmK-+b#R8x-QFIVkLur#m^nOU|Gvq+8gGZGeR)GEO&s=g!0pm}zd^=h zzYQOs<#z0r!oCZ&m3?2n{nY-$v747wLl@6t?22Axms^(nKBwsTm#zC5x~Df!x1N%$ zy}9q}DE<_KM|wuS4{u(4?q)5OyFPmB3Et*lxyDaPXTIe1ZU5*}W!7bbvnx6e{HVLo zVDV=DSK~AN1`ip2)??A*%5m|plRKp;#u;}E(9+pZ_qC;aLsB_6>;7| zs9SAacHqHZlFGF-t>XeauX#H4jm*?MYMahQx3=X)eU&@1k5 zD!BaD;XyHvIxe^{IjlzQ!)4cZwuescD1P@eeqtk@C zpyL+?ZTmE_mcR9?bI_{t^!omp&r)qC#aq{y?YEl!cE65I&msf4c*@@AYf1}?hJRkb z@wujw*Sr1DP=AfEr*E$wj#_n~CVZKb7W?L!#2tP5AMmYyWtp#?UiEnaJ^qB!%geWd zH>jyLcxY-r)v&x0vHpF<#7Ae-BmDZjtv6(}RnggOQJ;Ly?&`py2cC@_{f@o+K*fR5 zDwggckG>4McQ3P1ptGnOUdArep>s>A8rBuD&kUNC2yWn{C(WQA_yI#+$JUt+_r{U&?Az@|JZ{C?I zGdpFoVt2{Ux#rNRcZK_EYDP)!>x26kch%cpJRH}^rYck29^VpA0HdZ~Iuhm@H)(FYDU&igXOQLXA^x3xv?=`~-! zElsEcxEdnWa_|FxD}o<=kOqFq?F2tCO$GbW1-~KwR)XvT@LLu9=zt&iPowWl@0lN> zqE+P8(FE{+ydEqA+YyvefH~+ta(!()OHLE}OM{mZ2^Bjn0z!}!q%8vamqYIxwTp!N z297-f{0QzFio&nEZ(h`;4l7N6v(ba)7@s_0*j&+`9JLu7d zH4huKPBa$xbieOVYn#`lBJofC&su|$R8$v?ub5X8{yyipN!mDf&%mOi1>2NeY?cqd zbttx%U5lY>hq*U)>9Ef9 z8TY7qt=3Yj)VU89TBa4$4R{k)JvqMLhodk5^7|U(qhww*>cDCPH^Z@ur%K0bA+O#T zT`HOE=lOEkgXAwu)G2wD@77V*d{ut$a?)kq<1Ft(3!bDY?Wq5D+%`V$6Gd%Oz{>-* zkBUELoOGHQ+^~PW^|7um7DavbswtxzRrP$n@yw9N4tCv3m9D>U@4Rb{OK#~D<2%)} z)_zl@ZD%EK_o_1)N;_2hwRFJuw&x5xPI)qL-s?Zy=109KX?xUVMWNDhP4*O*%WV&T zRr>PqsY{>D_0MNIM2yM426U;pEs#eUwKzZD}+x;xouSLyxnfl8rOH<(%< zpW1Hz&N#JsWramCduz%bmbhPOH!$#9)|HvwYV|4_T8dBge6^-o@~Z|K>hw7u`MELF zC%n(C+O7B8Oy~F9r+A1G9>RFwTIizNF?Un--k!CTq`l^cV(eHG%DQp(&g(7bkhA4r z(6;1?{(t1ri(b@CHqSj+RdAf8r3ywBe&#l( zD3jb{r^DBj-)`LTdF_?O42@Ouz0T!6kL}v7r-%O0H;ebLD#=|L)@YERSMENWbJnJT zsn=n2-TXj#@w!2ea1@tTa-rav+XxmAXc|Uu;nydd}wN|m>=a+}qa&tEX zhFImY&KZyDb|qqYc2antR_C3oo2&n``36VpCT4$`5;iJhW{rAuz{Fz_-IG(bRXg_Z zGtjMw-~_%%PFff-;`ImHqA?ns`|pTysFC~9r+h+j$f+@RXNIp`X0#-v*JJ+|^U{^m zcYdnu^(An3@=JQ?!SwazHP=7H@b29FtKG6Wi@aV8kBqG7>(Jl0sBn4lle(TOqEv&| zn3v5n^Y?jFHhk2ZCf#`5ld&si_h{Yy8LTTGjD-lMdt z=eHMIM@&pI^wde{f7Q%E_vzOzxiik%^ecY+GIM|4XMEyS;xI6Xc`NwF?4s#Qu4}Jbeq`9={VMX^ z`vmxWOOG0Iy8Hg*9F4iU8j9~~w~gET?JuppCjHi%RmS9hw6B7m$JCyoem!Ddr&s# z*E=xs9~hq;ZSmK}Ma#F^J`3~Q)??5~XSda}QXW}9o^oqzN*jw8FQdKZ*&gzdAH-Hq zx&|IR#m2*@taw6osM<7MNBexl;5Xdq)IK`zT0mt4Lwt#?&kV5Gf?;WxuS>pvadw>(KFzAR(A*ORkDl%BSu zKULZheR$Hq6w}%>Hb!#YzQ`@g8M;Ab#b>1*%wtPF-+iWGG&J+9uK&7+pH6;}n;NvH zwBMTx4be)y6YJylYzYf8Ur~E~)*HPUg_I1Vp|zd!eC_U5y$rm0>`}r4?V(HJ_7B#K zeX#YC1N-XvC;jh^kjr$_-rDtAhdaI7ym6cQxbBKV>bBDhBMMGVIsf@mU9tOz19SB1 z2b{ehUAul;&i#|zO(%kb659OnI{bsjLW4A?wkkzo^D7ow)=w>Z^=ZX1E#9ZToYyJ$ z>ZT+l)|{HQZm5^3X;t27RtMu%pYCY_8pmWHHA6)mp{umzRTc6xs2K|K@-$tlwu*Yh zOmBIXqLPBVvK+AxsFk0k<4Mg@Qle%lyv$crkXKMp>o{@qrel9}*Mb$X=HxX&#Ymba zRb53fL`kKcLP!v;9kmVo&}gRtJT4@#DD2dpo43>!5{rMRZ> z$8xxA{sdYFsy-~I*iIWQH;lvKQ`}vt-3+v8R#Yo0&B}^qMY9bz(6+KCd{QUS%&Gm5 znp!CUSkXPhyL^XQu3 zT)wlHk>SfpJI3V4ISt-CqAksZl4_c0*mdVI|2FJiIcKk3Y?F1`U$-ulfAOZ8PfXhS zt=kG8UG|+7c3MGEUQWIs^G|AK0o4#Jk)e)K2POUC2DR%i+?l+5o!)~lf6X#CtFJN$ zrs~4%cJlJym6WN9;1|^hCYUI7q;|;A?{|?sI5$=O+uQhg7K8r$FxW3$Z4A`{7BEuk zP3=iF$?u+TG}CY_pP$^{(lUyhV8Mj@&mxMGXvqcJ$O0r$bzpg2*n<+-)HA7iDumaB z65ultmlAAlu$1z0ZjSu;b$2Q@EU@o8x7bj_ zJoxKhjxLRXV<=8Q`xmi+Z<)tqEj)|w7go%IZ|%{QI@s+Bf^u4S5T{Yq|P zmy*SyS{`%WQ(Qi+|C{lN{BjGEp|4hMROCdw-RNDYa_m6( zBO@a(&#BeR-u2eoOEKnhxVI_-Q%*SbTrj#ou4b*>TyMt(#RHx%%&=IxGU9F8-*0s^ zf}GcX3b@g2`}C#rtPY0yW!I#2e6Ve$TiHafF4Na%|E>RQ_N5Uy@3)7Rn<@A8+@X2X zXS0H?&9>PmnIYL8r+f2MUu8Y^f0qpKzyWHOVgZT=#c^}~HbUgmVlzSroJ@J@BB zF;(GNN9T`$>Q~ZTH!W|xbS7qXkN7qh3l3Cw>3iI0Y2HMw4TEz=UhQCSeYRZJ?{9tf zrPH0b??&rXrZZO6_f#wkS>QKXyDr++q`go3FvH^95ARp!T?i~YIwCN3fm#XW!`W?S z6i)IU7kTR3z3vxu*Eluwqnma<_3iJ{{W>?tbiH=gskDF5TU{Nw#hSaicd+1B4%EIK z*fq%GWm-8bv^`^PbvYwNOBFk6D&)g0LS?&+La3=9X@Od#Z>aFQtev1}eCN^onjD3KE=%%lkvpqj}CfAM(0ZzYey zjDjK;v`!4D!-79a6xav2>ws95!UMU{Ol~v>HO5wy%fVXWk zk&co%pf2nTloa$2N>h@dH2@n753~u46`adN9IbnHLV(SU_0ElH-{ViIzMSGX zEhmU_#i4xH;gtaz@!$J>2`f}qpKLHFv`shumAyG80|pmVa(X;^acOVzeO=Foz0cGo zrqw$mkTeb1H9Df4QixYQHljr8_lC8SF@< zNQ{hW6TSETo(GoiiJ*dH%)dxNKOga(Qf=*Q?ICqzMRl;EVxQE^RkY63jw%}J zi+g1+sW*$3m)Ft|GOlQYsLtRZC@E^$i;zB$g2E`Q{uEzkB5*;&rGVgUz++X^Sc<8z zfj&6RrYX{FC#nH#Rzpiqys`+v2aa9S1kk0mx>4*sx%;AC-b{M7-Y_%UJ!nV4*xC*U zkM7y`gnvJ%tBd*Eq~d~#^PEe$*SF{GtWe#$aL%6-E>A6Uy->IFz0QI~^-~u1FOA(+ zeNH}&*@bV=cW&j4Yj?UCuG=F2r)kcvl=a!}GYsy`&#PPD>l&8B(NgZDHS^oXoDB&_ zx9(bzwr0B)ToD= z@{eEbRJfx*r^I&V9=7joegAEgii=B^Dg}R?-1o#xe(Lk;!ah#7LtRoW7k({wDY?Dn z{Hsf`f7E#|NwPk1pjiH7Z#B2mJ*Lw=SDD(39dqM6Z{mbRcN{G~1dzH5mI^~j^72Y> zg)Q)Js{Bl2jCkQh@sbHB3VxbLvr^g7R2qSVx_hpAU4sgZb!GJMBfW$58G8@uS5UPe zN<>H~1*)6~{Unj%%92MYB8Wqk!SDdm{3e1z-%w5Q@c|Ut6&s&K3@VO5wf>t3RD?oQ z&7gLG0PP7WMlGra4huy^YC9q2D6b8(r4Wy1F`KmJ=ik0?1PGJscmA)X-S^$J(l}?iF=Mj-Prmb6vsN z^v+Mz^fLOSFRNIinNw|75dK+lSJ`dG+lmG8_*ja~nsg?nYo<~K;-Pz;b-d%2AW!s47o5n3YI&7JCqu$uR+s5}>G$i|7r*&K8 zdb{a7ee|c^7XAqH&&ENV9Jy=pUNHUN=;l_PT^SXE_;d}4oc}gs(y%l{IE*DBJ=lO)oEG!Mbs?)%?faH&G;9w ztb!U5^Alda`B@4*0d~dTwCaj9O~Hq%JhiLfLtUAsi=bv}stuq$ZEdLGR7+v563tkN za$)AHv0G|8hpg2*(k--Z%VP6Rbra78wOOvveT3<;XWO%>Be4om(dr5`e{h_Y`{^hu zbXL+ImOp99gX!wi=yxYt&o_6z*5`|_E!CXxMpvS+DKuZU-{$eIN7@zMXqV2~*f%JB z_Yl`7PUm(MQ5}5z!3icbFHg&o_XP*rd!S2NVge-?DU^j}RwV z&Jr&usKE?!O$#2J;6H9ewA*;MfFvt7f6H)Y$hZ(|2ay^BEwSD}8_1XjS|THM))1o@ z0BGfsDdC%Ev9qm?zvFeZDhWKeZo~<9?}}+_^{rhR-c`?A)7^DjBXp7VJ!{r;=>W}4^EUwvS8uG>cc@#9i? z2Ta|MeF=z9H?n=uS9{2kj`vJHrj1P9o62?S;C}1jgV8D_OQv5`e5+yL85F&3@2I-h zH+xXe=B%hG8dqpT@4U;kSN4mbE#3BZ`?NgNN1<}P(aypo?|l26Yi{Ml-8;Nuqv_hZ zJqI7&r&4;~zp`(-oj!eCmfi(wmfl$vO^hR?uBV_w%hD?YiF*V`18|+P^a?>zfr30Z zU4UDJZhAmH<=1*sT0Bu*4--7=%@=gMpjh9VFgcqc?Gq;M`&Yd*W23U zXK7yqw4nlc+CIlSP+cs1X{gH*yvz&@Td@yAzXt1BVHahhQF7 zRyJ1F;L&T1l7}`_d*st9oa#z5q;^3^r!O2Aj0XUCV1BMNoV?R$JrnCxai2hI$9npf z{h`yiuPW4bbZFCV#`=Wg7uMWiYP}ETMLYkQ(XVhs{8QuCJ#(3h8d+`1A5V`+V11f0 z!2WWv$r2;Ic|~C*m5CX3y@#%Cqf&Nwhlfqg8SdbFRkzD`Y4bKb@mun7Oyj|egF3q~ zN;Qt~zl8^$+O?bi*(y~1a|vI&U3dRYuXdLtSb2KuW!Nz5M>)6YnVh)z^D(k!5qfr~mnT_A?yTjp+5U@ll_9^<9^MDl#HV^pz@^s8XX^Lt@KF$&A{U zYMS3GzlVS#7G>x0@xzDk^n`qb8_`SqF*{$#c1cq|;b*3@H9KtSMNvKkAm~K7*T@Sw z+G$_4!_=_U5gltb+nhR;-FeK%4|49hZ38Yi)w-KGe9O7b+@o2mG4O@j@w*OwiIdyf zT#wq^C;0uI9dgddch2P<%Yw>@Ah1|$?kt7 ziCxZGzQM8H0=$k@0i*vlh6Shi4v$*f@Mf0+U$hFK&<2r)bRC*YOK)kmaHB8-XW!pZd1XCOKcb-M~X? z{wtSo9PMxAvEG$LyUo;aFv#qq0p+1vgNe-B|tE3fc+aLcxw)v;Sehk~}u5{q|l zvbE>laeA+EfittGullhrr*zV0&pT?oudI8!RcBt!$-6sgwOKDQou(f9kI*r~IzdRxD(M!I$hw}rbv#RG*o0MM5 z2dzrUJ4LPaIXr#=iYCQ*{SuMlzsu`am-bwf>DZYff%Mmz5P6&R={vCFl6))$h*Ey%QJL|L%+6DYg3X z4cDBPoJyP+%&2#tuXizZ)G9eGL;o`a&wqOI;g~ab@4kD_Y__z|-##jKlh(FX-B`s{ zx>Prtn(bHQuN2;OONy-gx;O)y)Vbdp0@VnoL=57e`UH~nf*BleC|Iur?Y#<@=McXyna;R*xX5%@%o`u zPsZz)@%sO#c>T021s6cc3_!R|v;SRcK|xLMoD@EI^E2mCI}0AhfY+og@&Imz+hiiF zsYC-(bfsdgJ(o7}b*=Y|Sa7cE`Oc4hWBveo5QN9L7Og84$PTEWa6|uziXZy!^YXk` z+jV?R@62mM|6ETb@qp$6WN9qFy4bt;m|V)q?{TXepRCiLpIzv=NTtoz&#tA);e)() z|245}c>lk3J~M`-nCw=XX%O=~+(HwpUE%Vmb4OZe427LPiq*xJ`e9eAlS z#QM0Z(U`o_@%kz?S;yO%HBQQA7Qe7OxY^=$ps(wUoPNF;B`!x*qF6?6rY+zuJ$iU3 zqr_ougx2_~O^nZ{mqb4eb}x+ZSpPC2&TM%10oOy9&vicW$;JP0&4OuXwlwCr)-Tze zzBcsC=kj?M5AEia<(BrdRdVOOnah9RoVoP&-z7DtyUeM4bD_(Cw2~{Ed{XSZc5Zq; z*E%+?uBO0T~2j5RgGY1_2oaWDt-+Kn4LB1Y{79K|lrp83beykU>BO0T~2j5RgGY M1_2oa{^Jn%e@Hx9#Q*>R literal 0 HcmV?d00001 diff --git a/XPLPro_Plugin_Source/SDK/SDKold/Libraries/Mac/XPWidgets.framework/XPWidgets b/XPLPro_Plugin_Source/SDK/SDKold/Libraries/Mac/XPWidgets.framework/XPWidgets new file mode 100644 index 0000000000000000000000000000000000000000..16944beff370b45ab41c9307ee8826beddd70124 GIT binary patch literal 195312 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//.xpl + +where ABI is one of mac_x64, win_x64 or lin_x64. The new schema is preferred, +so you can pack a version of your plugin that requires 3.0 with this scheme +and include a legacy 2.x plugin using hte old scheme for X-Plane 10 +compatibility. + +Please use the new scheme where possible - having a unique file name for each +DLL makes crash reports easier to read and triage. + +The 3.0 SDK drops support for 32-bit plugins; if you need to ship a 32-bit +plugin for 32-bit X-Plane 10, shipping using two schemes and two binaries may +be the best option. + +X-Plane SDK Release 2.1.3 11/14/13 + +Fixed XPC Wrappers to use int and intptr_t instead of long. This fixes +crashes for plugins on 64-bit Windows. + +X-Plane SDK Release 2.1.2 RC2 1/15/13 + +Removed headers from frameworks, as they don't work; updated README. + +X-Plane SDK Release 2.1.2 RC1 1/12/13 + +The 2.1.2 SDK adds frameworks for the XPLM and XPWidgets; Mac developers +can link directly against these frameworks and avoid unresolved symbols +and flat namespace problems. The frameworks produce plugins that will +work on X-Plane 8, 9, and 10 depending on the plugin CPU architecture, +minimum system SDK, and XPLM API revision number. + +X-Plane SDK Release 2.1.1 RC1 10/29/12 + +The 2.1.1 update to the SDK provides 64-bit build materials. + +X-Plane SDK Release 2.1.0 RC1 3/31/12 + +This is the first release of the version 2.1 X-Plane SDK. This version of the +SDK exposes new APIs. + +This API also replaces all references to "long" with int or intptr_t, +depending on whether the integer needs to be wide enough to hold coerced +pointers. Most of the time, int is used; the notable exception is the widgets +library where params and properties can contain pointers to user data. + +This change is not an ABI change - compiled plugins will work unmodified. +However for some compilers, you may need to replace long with int or intptr_t +in your code. + +X-Plane SDK Release 2.0.1 RC1 7/21/10 + +This release adds symbol visibility macros for GCC 4 on Linux and corrects a few +function documentation comments. + +X-Plane SDK Release 2.0 RC1 7/11/08 + +This release includes a corrected XPLM.lib for windows with exports for some of +the new 2.0 APIs. + +X-Plane SDK Release 2.0 Beta 2 4/23/08 + +This release includes new APIs for reading and writing data files and drawing +hooks for the local map screen, as well as some minor tweaks: + +- Sim version is 2.0 in the headers. +- unload plane msg marked as 2.0 only. +- New enumerations for additional languages. +- Function level docs improved. + +X-Plane SDK Release 2.0 Beta 1 1/19/08 + +This is the first release of the version 2.0 X-Plane SDK. CFM support has +been removed, and the license has been simplified, reflecting that it only has +to cover the SDK include/import lib files and not the sample code or examples. + +X-Plane SDK Release 1.0.2 1/5/05 + +The headers of the SDK are modified to support Kylix. No changes for Mac, +Windows, or C users. Headers now have SDK version numbers. + +X-Plane SDK Release 1.0.1 12/29/04 + +The headers of this SDK are modified to support Linux complication. No changes +for Mac and Windows users. + +X-Plane SDK Release Candidate 1 + +Only one slight change in the enums: the enum xpProperty_SubWindowHasCloseBoxes +in XPStandardWidgets.h has been changed to xpProperty_MainWindowHasCloseBoxes. +Its value has not been changed, so you will need to search-and-replace your code +when using this version of the SDK, but already-compiled plugins will experience +no different operation. + +The documentation has been revised for all headers to revise changes made to the +SDK over the course of beta. + +X-Plane SDK Beta 5 + +This version of the SDK features a number of enumeration changes to reflect the +X-Plane interface more correctly. This became crucial when X-Plane 7's new user +interface was released. With X-Plane in release candidates hopefully beta 5 of +the SDK could be the last one. Please see: + +www.xsquawkbox.net/xpsdk/newui.html + +For a comprehensive description of all the enumeration changes. For most +plugins (no developers reported using the deprecated enumerations), a simple +search and replace should suffice. Plugins compiled against the beta 4 SDK that +do not use now-unsupported graphics will continue to work correctly. + +X-Plane SDK Beta 4 + +This release corrects two problems with the Pascal headers: function pointer +types are now declared cdecl (since this is how the SDK calls them), and the +import library for the widget callbacks is now XPWIDGETS.DLL as it should be. + +X-Plane SDK Beta 3 + +This release finally features full documentation and a stable widgets API, as +well as a few other minor bug fixes. + +Starting with beta 3, the DLLs necessary to run plugins ship with X-Plane 660. +The SDK will work with X-Plane 660 RC3 and later. The XPWidgets DLL now lives +in the Resources/plugins folder. + +Starting with beta 3, extra plugins, documentation, sample code, and sample +projects are now featured directly on the web in the new X-Plane SDK library. +They are not included in the SDK zip file; the zip file only contains headers +and lib files for the SDK. + +X-Plane SDK Beta 2 + +You must recompile your plugin for the beta 2 plugin SDK! Plugins compiled +against the beta 1 SDK will not work with X-Plane 660 or the new XPLM.DLL. + +A huge number of data refs have been added. Unfortunately the documentation +is thin. Use the data ref tester plugin to view the data refs in real time +and find what you need. + +The data ref APIs have also changed to allow for arrays of integers as well +as floats. Some sim variables are now arrays that were previously many +individual items. + +A new drawing phase is available for replacing aircraft graphics. The +texturing APIs in XPLMGraphics have been revised. The most notable change is +that you cannot use the SDK to load your textures. (This functionality was +broken and never worked in beta 1.) See the x-plane-dev list for sample code +on how to load your own bitmaps. + +X-Plane can reload plugins on the fly. Use the Plugin Enabler plugin to reload +your plugin. On the Mac you can throw the old DLL in the trash and put a new +one in its place to reload a new version of the plugin. On the PC, an alert +comes up; while this alert is up you can swap your plugins' DLL. This allows +you to recompile your plugin without rebooting the sim. + +Delphi Pascal interfaces and sample code are in the SDK. Thanks to Billy +Verreynne for his hard work on this. + diff --git a/XPLPro_Plugin_Source/SDK/SDKold/license.txt b/XPLPro_Plugin_Source/SDK/SDKold/license.txt new file mode 100644 index 0000000..8b9cbfc --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/SDKold/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2008, Sandy Barbour and Ben Supnik +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Neither the names of the authors nor that of X-Plane or Laminar Research + may be used to endorse or promote products derived from this software + without specific prior written permission from the authors or + Laminar Research, respectively. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/XPLPro_Plugin_Source/SDK/license.txt b/XPLPro_Plugin_Source/SDK/license.txt new file mode 100644 index 0000000..8b9cbfc --- /dev/null +++ b/XPLPro_Plugin_Source/SDK/license.txt @@ -0,0 +1,27 @@ +Copyright (c) 2008, Sandy Barbour and Ben Supnik +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Neither the names of the authors nor that of X-Plane or Laminar Research + may be used to endorse or promote products derived from this software + without specific prior written permission from the authors or + Laminar Research, respectively. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/XPLPro_Plugin_Source/SerialClass.cpp b/XPLPro_Plugin_Source/SerialClass.cpp new file mode 100644 index 0000000..7ecc9ee --- /dev/null +++ b/XPLPro_Plugin_Source/SerialClass.cpp @@ -0,0 +1,168 @@ +#include "SerialClass.h" +#include "XPLProCommon.h" + +#include + +extern FILE* errlog; // Used for logging problems + +serialClass::serialClass() +{ + + +} + +serialClass::~serialClass() +{ + shutDown(); + +} + +int serialClass::begin(int portNumber) +{ + //We're not yet connected + this->connected = false; + this->status; + + //Form the Raw device name + + + sprintf_s(portName, 20, "\\\\.\\COM%u", portNumber); + + //Try to connect to the given port throuh CreateFile + this->hSerial = CreateFileA(portName, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + 0, //FILE_FLAG_OVERLAPPED, + NULL); + + //Check if the connection was successfull + if (this->hSerial == INVALID_HANDLE_VALUE) + { + return -1; + } + else + { + //If connected we try to set the comm parameters + DCB dcbSerialParams = { 0 }; + + //Try to get the current + if (!GetCommState(this->hSerial, &dcbSerialParams)) + { + //If impossible, show an error + //printf("failed to get current serial parameters!"); + } + else + { + //Define serial connection parameters for the arduino board + dcbSerialParams.BaudRate = XPL_BAUDRATE; + dcbSerialParams.ByteSize = 8; + dcbSerialParams.StopBits = ONESTOPBIT; + dcbSerialParams.Parity = NOPARITY; + //Setting the DTR to Control_Enable ensures that the Arduino is properly + //reset upon establishing a connection + dcbSerialParams.fDtrControl = DTR_CONTROL_ENABLE; + + //Set the parameters and check for their proper application + if (!SetCommState(hSerial, &dcbSerialParams)) + { + // printf("ALERT: Could not set Serial Port parameters"); + } + else + { + //If everything went fine we're connected + this->connected = true; + //Flush any remaining characters in the buffers + PurgeComm(this->hSerial, PURGE_RXCLEAR | PURGE_TXCLEAR); + //We wait 2s as the arduino board will be resetting + Sleep(ARDUINO_WAIT_TIME); + fprintf(errlog, "Serial: port \"%s\" opened successfully.\n", portName); + return portNumber; + } + } + } + return -1; // general error code +} + +int serialClass::shutDown(void) +{ + //Check if we are connected before trying to disconnect + if (this->connected) + { + //We're no longer connected + this->connected = false; + //Close the serial handler + CloseHandle(this->hSerial); + fprintf(errlog, "...Closing port %s\n", portName); + + } + return 0; +} + + + +int serialClass::readData(char* buffer, size_t nbChar) +{ + //Number of bytes we'll have read + DWORD bytesRead; + //Number of bytes we'll really ask to read + size_t toRead; + + //Use the ClearCommError function to get status info on the Serial port + ClearCommError(this->hSerial, &this->errors, &this->status); + + //Check if there is something to read + if (this->status.cbInQue > 0) + { + //If there is we check if there is enough data to read the required number + //of characters, if not we'll read only the available characters to prevent + //locking of the application. + if (this->status.cbInQue > nbChar) + { + toRead = nbChar; + } + else + { + toRead = this->status.cbInQue; + } + + //Try to read the require number of chars, and return the number of read bytes on success + if (ReadFile(this->hSerial, buffer, toRead, &bytesRead, NULL)) + { + return bytesRead; + } + + } + + //If nothing has been read, or that an error was detected return 0 + return 0; + +} + + +bool serialClass::writeData(const char* buffer, size_t nbChar) +{ + DWORD bytesSend; + + //Try to write the buffer on the Serial port + if (!WriteFile(this->hSerial, (void*)buffer, nbChar, &bytesSend, 0)) + { + //In case it doesnt work get comm error and return false + ClearCommError(this->hSerial, &this->errors, &this->status); + + return false; + } + else + { + // FlushFileBuffers(this->hSerial); + return true; + } +} + +bool serialClass::IsConnected(void) +{ + //Simply return the connection status + return this->connected; +} + diff --git a/XPLPro_Plugin_Source/SimData.vcxproj b/XPLPro_Plugin_Source/SimData.vcxproj new file mode 100644 index 0000000..edae193 --- /dev/null +++ b/XPLPro_Plugin_Source/SimData.vcxproj @@ -0,0 +1,303 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + + + 10.0 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69} + XPLProPlugin + + + + DynamicLibrary + false + MultiByte + v142 + + + DynamicLibrary + false + MultiByte + v142 + + + DynamicLibrary + false + MultiByte + v142 + + + DynamicLibrary + false + MultiByte + v142 + + + + + + + + + + + + + + + + + + + + + + + ..\..\..\..\..\..\X-Plane 12\Resources\plugins\XPLPro\64\ + .\Release\64\ + false + .xpl + false + win + + + false + .xpl + false + win + ..\..\X-Plane 10\Resources\plugins\XPLCore\32 + .\release\32\ + + + ..\..\X-Plane 10\Resources\plugins\XPLDirect\64\ + .\Debug\64\ + false + .xpl + false + win + + + false + .xpl + false + win + + + + MultiThreadedDLL + AnySuitable + true + true + MaxSpeed + true + Level3 + SDK\CHeaders\XPLM;SDK\CHeaders\Widgets;%(AdditionalIncludeDirectories) + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;WIN32;NDEBUG;_WINDOWS;_USRDLL;SIMDATA_EXPORTS;IBM=1;XPLM100=1;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + .\Release\64\ + .\Release\64\SimData.pch + + + .\Release\64\ + .\Release\64\ + Default + true + Speed + true + false + + + true + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;NDEBUG;%(PreprocessorDefinitions) + .\Release\SimData.tlb + true + + + 0x0809 + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\SimData.bsc + + + true + true + Console + .\Release\64\SimData.lib + SDK\Libraries\Win;%(AdditionalLibraryDirectories) + Opengl32.lib;odbc32.lib;odbccp32.lib;XPLM_64.lib;XPWidgets_64.lib;libconfig.lib;%(AdditionalDependencies) + + + + + MultiThreadedDLL + AnySuitable + true + true + MaxSpeed + true + Level3 + SDK\CHeaders\XPLM;SDK\CHeaders\Widgets;%(AdditionalIncludeDirectories) + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;WIN32;NDEBUG;_WINDOWS;_USRDLL;SIMDATA_EXPORTS;IBM=1;XPLM100=1;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions) + .\Release\64\ + .\Release\64\SimData.pch + + + .\Release\64\ + .\Release\64\ + Default + true + Speed + true + + + true + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;NDEBUG;%(PreprocessorDefinitions) + .\Release\SimData.tlb + true + + + 0x0809 + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;NDEBUG;%(PreprocessorDefinitions) + + + true + .\Release\SimData.bsc + + + true + true + Console + .\Release\64\SimData.lib + SDK\Libraries\Win;%(AdditionalLibraryDirectories) + Opengl32.lib;odbc32.lib;odbccp32.lib;XPLM_64.lib;XPWidgets_64.lib;%(AdditionalDependencies) + + + + + MultiThreadedDebugDLL + Default + false + Disabled + true + OldStyle + SDK\CHeaders\XPLM;SDK\CHeaders\Widgets;%(AdditionalIncludeDirectories) + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;WIN32;_DEBUG;_WINDOWS;_USRDLL;SIMDATA_EXPORTS;IBM=1;XPLM100=1;%(PreprocessorDefinitions) + .\Debug\64\ + .\Debug\64\SimData.pch + + + .\Debug\64\ + .\Debug\64\ + EnableFastChecks + Default + Level3 + + + true + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;_DEBUG;%(PreprocessorDefinitions) + .\Debug\SimData.tlb + true + + + 0x0809 + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;_DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\SimData.bsc + + + true + true + true + Console + .\Debug\64\SimData.lib + SDK\Libraries\Win;%(AdditionalLibraryDirectories) + Opengl32.lib;odbc32.lib;odbccp32.lib;XPLM_64.lib;XPWidgets_64.lib;%(AdditionalDependencies) + + + + + MultiThreadedDebugDLL + Default + false + Disabled + true + OldStyle + SDK\CHeaders\XPLM;SDK\CHeaders\Widgets;%(AdditionalIncludeDirectories) + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;WIN32;_DEBUG;_WINDOWS;_USRDLL;SIMDATA_EXPORTS;IBM=1;XPLM100=1;%(PreprocessorDefinitions) + .\Debug\64\ + .\Debug\64\SimData.pch + + + .\Debug\64\ + .\Debug\64\ + EnableFastChecks + Default + Level3 + + + true + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;_DEBUG;%(PreprocessorDefinitions) + .\Debug\SimData.tlb + true + + + 0x0809 + WINVER=0x0601;_WIN32_WINNT=0x0601;_WIN32_WINDOWS=0x0601;_DEBUG;%(PreprocessorDefinitions) + + + true + .\Debug\SimData.bsc + + + true + true + true + Console + .\Debug\64\SimData.lib + SDK\Libraries\Win;%(AdditionalLibraryDirectories) + Opengl32.lib;odbc32.lib;odbccp32.lib;XPLM_64.lib;XPWidgets_64.lib;%(AdditionalDependencies) + + + + + + + + false + false + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/XPLPro_Plugin_Source/StatusWindow.cpp b/XPLPro_Plugin_Source/StatusWindow.cpp new file mode 100644 index 0000000..1fbf38e --- /dev/null +++ b/XPLPro_Plugin_Source/StatusWindow.cpp @@ -0,0 +1,176 @@ + +#include +#include +#include + + + +#define XPLM200 + +#include "XPLProCommon.h" +#include "XPLMPlugin.h" +#include "XPLMDataAccess.h" +#include "XPLMDisplay.h" +#include "XPLMGraphics.h" +#include "XPLMMenus.h" + +#include "XPWidgets.h" +#include "XPStandardWidgets.h" + +#include "XPLMUtilities.h" +#include "XPLMProcessing.h" + +#include "XPLMCamera.h" +#include "XPUIGraphics.h" +#include "XPWidgetUtils.h" + + +#include "serialclass.h" +#include "Config.h" + +#include "XPLProPlugin.h" + +#include "DataTransfer.h" +#include "StatusWindow.h" + +XPLMWindowID statusWindow = NULL; + +extern CommandBinding myCommands[XPL_MAXCOMMANDS_PC]; +extern DataRefBinding myBindings[XPL_MAXDATAREFS_PC]; + + +extern long int packetsSent; +extern long int packetsReceived; +extern int validPorts; + +extern long cycleCount; +extern float elapsedTime; + +extern int cmdHandleCounter; +extern int refHandleCounter; + +int lastCmdAction = -1; +int lastRefSent = -1; +int lastRefElementSent = 0; +int lastRefReceived = -1; +int lastRefElementReceived = 0; + + +void statusWindowCreate() +{ + statusWindow = XPLMCreateWindow( + 50, 600, 800, 200, /* Area of the window. */ + 1, /* Start visible. */ + statusDrawWindowCallback, /* Callbacks */ + statusHandleKeyCallback, + statusHandleMouseClickCallback, + NULL); /* Refcon - not used. */ +} + +/**************************************************************************************/ +/* MyDrawWindowCallback -- Called by xplane while window is active */ +/**************************************************************************************/ +void statusDrawWindowCallback( + XPLMWindowID inWindowID, + void* inRefcon) +{ + int left, top, right, bottom; + float color[] = { 1.0, 1.0, 1.0 }; /* RGB White */ + char tstring[800]; + + /* First we get the location of the window passed in to us. */ + XPLMGetWindowGeometry(inWindowID, &left, &top, &right, &bottom); + + /* We now use an XPLMGraphics routine to draw a translucent dark + * rectangle that is our window's shape. */ + XPLMDrawTranslucentDarkBox(left, top, right, bottom); + + /* Finally we draw the text into the window, also using XPLMGraphics + * routines. The NULL indicates no word wrapping. */ + XPLMDrawString(color, left + 5, top - 20, "Curiosity Workshop XPLPro Arduino Interface. Updates and Examples: www.patreon.com/curiosityworkshop", NULL, xplmFont_Basic); + + + sprintf(tstring, "Distribution Build: %u. Click this window when complete", XPL_VERSION); + XPLMDrawString(color, left + 5, top - 35, tstring, NULL, xplmFont_Basic); + + + sprintf(tstring, "Devices Detected: %i, Registered DataRefs: %i, Registered Commands: %i, tx: %i, rx: %i", validPorts, refHandleCounter, cmdHandleCounter, packetsSent, packetsReceived); + XPLMDrawString(color, left + 5, top - 55, tstring, NULL, xplmFont_Basic); + sprintf(tstring, "Elapsed time since start: %i, cycles: %i, average time between cycles: %3.2f", (int)elapsedTime, cycleCount, elapsedTime / cycleCount); + XPLMDrawString(color, left + 5, top - 70, tstring, NULL, xplmFont_Basic); + + if (lastRefReceived >= 0) + { + //sprintf(tstring, "Last ref received: %i, %s\n", lastRefReceived, myBindings[lastRefReceived].xplaneDataRefName); + + if (myBindings[lastRefReceived].xplaneDataRefTypeID & xplmType_Int) sprintf(tstring, "Last Dataref Received: %s, %i", myBindings[lastRefReceived].xplaneDataRefName, myBindings[lastRefReceived].currentReceivedl[lastRefElementReceived]); + if (myBindings[lastRefReceived].xplaneDataRefTypeID & xplmType_Float) sprintf(tstring, "Last Dataref Received: %s, %f", myBindings[lastRefReceived].xplaneDataRefName, myBindings[lastRefReceived].currentReceivedf[lastRefElementReceived]); + if (myBindings[lastRefReceived].xplaneDataRefTypeID & xplmType_Double) sprintf(tstring, "Last Dataref Received: %s, %i", myBindings[lastRefReceived].xplaneDataRefName, myBindings[lastRefReceived].currentReceivedl[lastRefElementReceived]); + if (myBindings[lastRefReceived].xplaneDataRefTypeID & xplmType_IntArray) sprintf(tstring, "Last Dataref Received: %s, Element: %i, %i", myBindings[lastRefReceived].xplaneDataRefName, lastRefElementReceived, myBindings[lastRefReceived].currentReceivedl[lastRefElementReceived]); + if (myBindings[lastRefReceived].xplaneDataRefTypeID & xplmType_FloatArray) sprintf(tstring, "Last Dataref Received: %s, Element: %i, %f", myBindings[lastRefReceived].xplaneDataRefName, lastRefElementReceived, myBindings[lastRefReceived].currentReceivedf[lastRefElementReceived]); + // if (myBindings[lastRefReceived].xplaneDataRefTypeID & xplmType_Data) sprintf(tstring, "Last Dataref Action: %s, %s", myBindings[lastRefReceived].xplaneDataRefName, myBindings[lastRefReceived].xplaneCurrentReceiveds); + XPLMDrawString(color, left + 5, top - 90, tstring, NULL, xplmFont_Basic); + + } + + if (lastRefSent >= 0) + { + //sprintf(tstring, "Last ref sent: %i, %s\n", lastRefReceived, myBindings[lastRefReceived].xplaneDataRefName); + + if (myBindings[lastRefSent].xplaneDataRefTypeID & xplmType_Int) sprintf(tstring, "Last Dataref Sent: %s, %i", myBindings[lastRefSent].xplaneDataRefName, myBindings[lastRefSent].currentSentl[lastRefElementSent]); + if (myBindings[lastRefSent].xplaneDataRefTypeID & xplmType_Float) sprintf(tstring, "Last Dataref Sent: %s, %f", myBindings[lastRefSent].xplaneDataRefName, myBindings[lastRefSent].currentSentf[lastRefElementSent]); + if (myBindings[lastRefSent].xplaneDataRefTypeID & xplmType_Double) sprintf(tstring, "Last Dataref Sent: %s, %i", myBindings[lastRefSent].xplaneDataRefName, myBindings[lastRefSent].currentSentl[lastRefElementSent]); + if (myBindings[lastRefSent].xplaneDataRefTypeID & xplmType_IntArray) sprintf(tstring, "Last Dataref Sent: %s, Element: %i, %i", myBindings[lastRefSent].xplaneDataRefName, lastRefElementSent, myBindings[lastRefSent].currentSentl[lastRefElementSent]); + if (myBindings[lastRefSent].xplaneDataRefTypeID & xplmType_FloatArray) sprintf(tstring, "Last Dataref Sent: %s, Element: %i, %f", myBindings[lastRefSent].xplaneDataRefName, lastRefElementSent, myBindings[lastRefSent].currentSentf[lastRefElementSent]); + if (myBindings[lastRefSent].xplaneDataRefTypeID & xplmType_Data) sprintf(tstring, "Last Dataref Sent: %s, %s", myBindings[lastRefSent].xplaneDataRefName, myBindings[lastRefSent].currentSents[lastRefElementSent]); + XPLMDrawString(color, left + 5, top - 105, tstring, NULL, xplmFont_Basic); + + } + + if (lastCmdAction >= 0) + { + sprintf(tstring, "Last Command Action: %s, accumulator: %i", myCommands[lastCmdAction].xplaneCommandName, myCommands[lastCmdAction].accumulator); + XPLMDrawString(color, left + 5, top - 120, tstring, NULL, xplmFont_Basic); + } + + + +} + +int statusWindowActive(void) +{ + if (!statusWindow) return 0; + else return 1; +} + + +/**************************************************************************************/ +/* MyHandleMouseClickCallback -- Called by xplane while status window is active */ +/**************************************************************************************/ +int statusHandleMouseClickCallback( + XPLMWindowID inWindowID, + int x, + int y, + XPLMMouseStatus inMouse, + void* inRefcon) +{ + + XPLMDestroyWindow(statusWindow); + statusWindow = NULL; + + return 1; +} + +/**************************************************************************************/ +/* MyHandleKeyCallback -- Called by xplane while status window is active */ +/**************************************************************************************/ +void statusHandleKeyCallback( + XPLMWindowID inWindowID, + char inKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void* inRefcon, + int losingFocus) +{ +} + diff --git a/XPLPro_Plugin_Source/StatusWindow.h b/XPLPro_Plugin_Source/StatusWindow.h new file mode 100644 index 0000000..e8b0ee5 --- /dev/null +++ b/XPLPro_Plugin_Source/StatusWindow.h @@ -0,0 +1,16 @@ +#pragma once + + + +void statusWindowCreate(void); +int statusWindowActive(void); + +void statusDrawWindowCallback( XPLMWindowID, void*); +int statusHandleMouseClickCallback(XPLMWindowID, int , int , XPLMMouseStatus , void*); +void statusHandleKeyCallback( + XPLMWindowID inWindowID, + char inKey, + XPLMKeyFlags inFlags, + char inVirtualKey, + void* inRefcon, + int losingFocus); \ No newline at end of file diff --git a/XPLPro_Plugin_Source/XPLDevice.cpp b/XPLPro_Plugin_Source/XPLDevice.cpp new file mode 100644 index 0000000..d02a584 --- /dev/null +++ b/XPLPro_Plugin_Source/XPLDevice.cpp @@ -0,0 +1,678 @@ + +#define XPLM200 + +#include "XPLMPlugin.h" +#include "XPLMDataAccess.h" +#include "XPLMDisplay.h" +#include "XPLMGraphics.h" +#include "XPLMMenus.h" + +#include "XPWidgets.h" +#include "XPStandardWidgets.h" + +#include "XPLMUtilities.h" +#include "XPLMProcessing.h" + +#include "XPLMCamera.h" +#include "XPUIGraphics.h" +#include "abbreviations.h" +#include "XPWidgetUtils.h" + +#include "DataTransfer.h" +#include "XPLDevice.h" + +extern long int packetsSent; +extern long int packetsReceived; +extern FILE* serialLogFile; // for serial data log +extern FILE* errlog; // Used for logging problems +extern abbreviations gAbbreviations; +extern float elapsedTime; + +extern int refHandleCounter; +extern int cmdHandleCounter; + +extern CommandBinding myCommands[XPL_MAXCOMMANDS_PC]; +extern DataRefBinding myBindings[XPL_MAXDATAREFS_PC]; + +extern int lastRefReceived; +extern int lastRefSent; +extern int lastCmdAction; +extern int lastRefElementSent; +extern int lastRefElementReceived; + +XPLDevice::XPLDevice(int inReference) +{ + bufferPosition = 0; + readBuffer[0] = '\0'; + lastDebugMessageReceived[0] = '\0'; + RefsLoaded = 0; + lastSendTime = 0; + _referenceID = inReference; + + _active = 0; + _flightLoopPause = 0; + + minTimeBetweenFrames = XPL_MILLIS_BETWEEN_FRAMES_DEFAULT; + +} + +XPLDevice::~XPLDevice() +{ + //if (Port) delete Port; + +} + +int XPLDevice::isActive(void) +{ + + return _active; + +} + +void XPLDevice::setActive(int flag) +{ + _active = flag; + +} + + +void XPLDevice::processSerial(void) +{ + do + { + while (port->readData(&readBuffer[bufferPosition], 1)) + { + readBuffer[bufferPosition + 1] = '\0'; + //fprintf(errlog, "Buffer currently: %s\r\n", readBuffer); + + + if (readBuffer[0] != XPL_PACKETHEADER) + { + readBuffer[0] = '\0'; + bufferPosition = -1; + } + + + if (readBuffer[0] == XPL_PACKETHEADER + && readBuffer[bufferPosition] == XPL_PACKETTRAILER) + + { + + _processPacket(); + readBuffer[0] = '\0'; + bufferPosition = -1; + } + + + if (strlen(readBuffer) >= XPLMAX_PACKETSIZE) + { + readBuffer[0] = '\0'; // packet size exceeded / bad packet + bufferPosition = -1; + } + + + bufferPosition++; + readBuffer[bufferPosition] = '\0'; + } + + } while (_flightLoopPause); + +} + + + +void XPLDevice::_processPacket(void) +{ + + char writeBuffer[XPLMAX_PACKETSIZE]; + char speechBuf[XPLMAX_PACKETSIZE]; + + int bindingNumber; + long int rate; + float precision; + int element; + + packetsReceived++; + + + if (!port) return; + +// fprintf(errlog, "_processPacket: %s \r\n", readBuffer); + + if (serialLogFile) fprintf(serialLogFile, "et: %5.0f rx port: %s length: %3.3i buffer: %s\n", elapsedTime, port->portName, (int)strlen(readBuffer), readBuffer); + + + readBuffer[bufferPosition+1] = 0; // terminate the string just in case + + + switch (readBuffer[1]) + { + + case XPLREQUEST_REGISTERDATAREF: + { + + _parseString(myBindings[refHandleCounter].xplaneDataRefName, readBuffer,2, 80 ); + //_parseInt(&myBindings[refHandleCounter].RWMode, readBuffer, 3); + + fprintf(errlog, "\n Device %s is requesting handle for dataref: \"%s\"...", deviceName, myBindings[refHandleCounter].xplaneDataRefName); + + myBindings[refHandleCounter].xplaneDataRefHandle = XPLMFindDataRef(myBindings[refHandleCounter].xplaneDataRefName); + if (myBindings[refHandleCounter].xplaneDataRefHandle == NULL) // if not found, try searching the abbreviations file before giving up + { + gAbbreviations.convertString(myBindings[refHandleCounter].xplaneDataRefName); + myBindings[refHandleCounter].xplaneDataRefHandle = XPLMFindDataRef(myBindings[refHandleCounter].xplaneDataRefName); + } + + if (myBindings[refHandleCounter].xplaneDataRefHandle != NULL) + { + fprintf(errlog, "I found that DataRef!\n"); + + myBindings[refHandleCounter].bindingActive = 1; + myBindings[refHandleCounter].deviceIndex = _referenceID; + //myBindings[refHandleCounter].xplaneDataRefArrayOffset = atoi(arrayReference); + //myBindings[refHandleCounter].divider = atof(dividerString); + //myBindings[refHandleCounter].RWMode = readBuffer[2] - '0'; + //fprintf(errlog, "RWMode %c was saved as int %i\r\n", strippedPacket[1], myBindings[refHandleCounter].RWMode); + myBindings[refHandleCounter].xplaneDataRefTypeID = XPLMGetDataRefTypes(myBindings[refHandleCounter].xplaneDataRefHandle); + + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",%i", refHandleCounter); + + _writePacket(XPLRESPONSE_DATAREF, writeBuffer); + + fprintf(errlog, " I responded with %3.3i as a handle using this packet: %s\n", refHandleCounter, writeBuffer); + if (myBindings[refHandleCounter].xplaneDataRefTypeID & xplmType_Int) fprintf(errlog, " This dataref returns that it is of type: int\n"); + if (myBindings[refHandleCounter].xplaneDataRefTypeID & xplmType_Float) fprintf(errlog, " This dataref returns that it is of type: float\n"); + if (myBindings[refHandleCounter].xplaneDataRefTypeID & xplmType_Double) fprintf(errlog, " This dataref returns that it is of type: double\n"); + if (myBindings[refHandleCounter].xplaneDataRefTypeID & xplmType_FloatArray) fprintf(errlog, " This dataref returns that it is of type: floatArray\n"); + if (myBindings[refHandleCounter].xplaneDataRefTypeID & xplmType_IntArray) fprintf(errlog, " This dataref returns that it is of type: intArray\n"); + if (myBindings[refHandleCounter].xplaneDataRefTypeID & xplmType_Data) + { + fprintf(errlog, " This dataref returns that it is of type: data ***Currently supported only for data sent from xplane (read only)***\n"); + myBindings[refHandleCounter].currentSents[0] = (char*)malloc(XPLMAX_PACKETSIZE - 5); + } + + + refHandleCounter++; + } + else + { + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",-02,\"%s\"", myBindings[refHandleCounter].xplaneDataRefName); + _writePacket(XPLRESPONSE_DATAREF, writeBuffer); + myBindings[refHandleCounter].bindingActive = 0; + fprintf(errlog, " requested DataRef not found, sorry. \n I sent back data frame: %s\n", writeBuffer); + refHandleCounter++; // to avoid timeout + } + + + break; + } + + case XPLREQUEST_UPDATES: + + + _parseInt(&bindingNumber, readBuffer, 2); + _parseInt(&rate, readBuffer, 3); + _parseFloat(&precision, readBuffer, 4); + + myBindings[bindingNumber].readFlag[0] = 1; + myBindings[bindingNumber].updateRate = rate; + myBindings[bindingNumber].precision = precision; + fprintf(errlog, " Device requested that %s dataref be updated at rate: %i and precision %f\n", myBindings[bindingNumber].xplaneDataRefName, rate, precision); + + break; + + case XPLREQUEST_UPDATESARRAY: + + + _parseInt(&bindingNumber, readBuffer, 2); + _parseInt(&rate, readBuffer, 3); + _parseFloat(&precision, readBuffer, 4); + _parseInt(&element, readBuffer, 5); + + myBindings[bindingNumber].readFlag[element] = 1; + myBindings[bindingNumber].updateRate = rate; + myBindings[bindingNumber].precision = precision; + fprintf(errlog, " Device requested that %s dataref element %i be updated at rate: %i and precision %f\n", myBindings[bindingNumber].xplaneDataRefName, element, rate, precision); + + break; + + case XPLREQUEST_SCALING: + _parseInt(&bindingNumber, readBuffer, 2); + _parseInt(&myBindings[bindingNumber].scaleFromLow, readBuffer, 3); + _parseInt(&myBindings[bindingNumber].scaleFromHigh, readBuffer, 4); + _parseInt(&myBindings[bindingNumber].scaleToLow, readBuffer, 5); + _parseInt(&myBindings[bindingNumber].scaleToHigh, readBuffer, 6); + myBindings[bindingNumber].scaleFlag = 1; + + break; + + case XPLREQUEST_REGISTERCOMMAND: + { + + _parseString(myCommands[cmdHandleCounter].xplaneCommandName, readBuffer, 2, 80); + + fprintf(errlog, " Device %s is requesting command: %s...", deviceName, myCommands[cmdHandleCounter].xplaneCommandName); + + myCommands[cmdHandleCounter].xplaneCommandHandle = XPLMFindCommand(myCommands[cmdHandleCounter].xplaneCommandName); + if (myCommands[cmdHandleCounter].xplaneCommandHandle == NULL) // if not found, try searching the abbreviations file before giving up + { + gAbbreviations.convertString(myCommands[cmdHandleCounter].xplaneCommandName); + myCommands[cmdHandleCounter].xplaneCommandHandle = XPLMFindCommand(myCommands[cmdHandleCounter].xplaneCommandName); + } + + + + if (myCommands[cmdHandleCounter].xplaneCommandHandle != NULL) + { + fprintf(errlog, "I found that Command!\n"); + + myCommands[cmdHandleCounter].bindingActive = 1; + myCommands[cmdHandleCounter].deviceIndex = _referenceID; + + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",%i", cmdHandleCounter); + + _writePacket(XPLRESPONSE_COMMAND, writeBuffer); + + //if (!myXPLDevices[port].Port->WriteData(writeBuffer, strlen(writeBuffer))) + // fprintf(errlog, " Problem occurred sending handle to the device, sorry.\n"); + //else + { + fprintf(errlog, " I responded with %3.3i as a handle using this packet: %s\n", cmdHandleCounter, writeBuffer); + } + + cmdHandleCounter++; + } + else + + { + sprintf_s(writeBuffer, XPLMAX_PACKETSIZE, ",-02,\"%s\"", &readBuffer[2]); + _writePacket(XPLRESPONSE_COMMAND, writeBuffer); + myCommands[cmdHandleCounter].bindingActive = 0; + fprintf(errlog, " requested Command not found, sorry. \n I sent back data frame: %s\n", writeBuffer); + cmdHandleCounter++; + } + + + break; + } + + case XPLCMD_DATAREFUPDATEINT: + case XPLCMD_DATAREFUPDATEFLOAT: + case XPLCMD_DATAREFUPDATEFLOATARRAY: + case XPLCMD_DATAREFUPDATEINTARRAY: + { + + float tempFloat; + int tempInt; + int tempElement; + + // fprintf(errlog, "Device is sending dataRef update with packet: %s \r\n", strippedPacket); + + _parseInt(&bindingNumber, readBuffer, 2); + + if (bindingNumber < 0 && bindingNumber > refHandleCounter) break; + + lastRefReceived = bindingNumber; // for the status window + + if (myBindings[bindingNumber].xplaneDataRefTypeID & xplmType_Int) + { + _parseInt(&tempInt, readBuffer, 3); + if (myBindings[bindingNumber].scaleFlag) tempInt = mapInt(tempInt, myBindings[bindingNumber].scaleFromLow, + myBindings[bindingNumber].scaleFromHigh, + myBindings[bindingNumber].scaleToLow, + myBindings[bindingNumber].scaleToHigh); + + XPLMSetDatai(myBindings[bindingNumber].xplaneDataRefHandle, tempInt); + myBindings[bindingNumber].currentReceivedl[0] = tempInt; + myBindings[bindingNumber].currentSentl[0] = tempInt; + } + + if (myBindings[bindingNumber].xplaneDataRefTypeID & xplmType_Float) + { + + _parseFloat(&tempFloat, readBuffer, 3); + if (myBindings[bindingNumber].scaleFlag) tempFloat = mapFloat(tempFloat, myBindings[bindingNumber].scaleFromLow, + myBindings[bindingNumber].scaleFromHigh, + myBindings[bindingNumber].scaleToLow, + myBindings[bindingNumber].scaleToHigh); + + + XPLMSetDataf(myBindings[bindingNumber].xplaneDataRefHandle, tempFloat); + myBindings[bindingNumber].currentReceivedf[0] = tempFloat; + myBindings[bindingNumber].currentSentf[0] = tempFloat; + } + + if (myBindings[bindingNumber].xplaneDataRefTypeID & xplmType_Double) + { + _parseFloat(&tempFloat, readBuffer, 3); + if (myBindings[bindingNumber].scaleFlag) tempFloat = mapFloat(tempFloat, myBindings[bindingNumber].scaleFromLow, + myBindings[bindingNumber].scaleFromHigh, + myBindings[bindingNumber].scaleToLow, + myBindings[bindingNumber].scaleToHigh); + XPLMSetDatad(myBindings[bindingNumber].xplaneDataRefHandle, tempFloat); + myBindings[bindingNumber].currentReceivedf[0] = tempFloat; + myBindings[bindingNumber].currentSentf[0] = tempFloat; + + } + + + if (myBindings[bindingNumber].xplaneDataRefTypeID & xplmType_IntArray) + { + _parseInt(&tempInt, readBuffer, 3); + _parseInt(&tempElement, readBuffer, 4);// need error checking here + + if (myBindings[bindingNumber].scaleFlag) tempInt = mapInt(tempInt, myBindings[bindingNumber].scaleFromLow, + myBindings[bindingNumber].scaleFromHigh, + myBindings[bindingNumber].scaleToLow, + myBindings[bindingNumber].scaleToHigh); + + XPLMSetDatavi(myBindings[bindingNumber].xplaneDataRefHandle, &tempInt, tempElement, 1); + myBindings[bindingNumber].currentReceivedl[tempElement] = tempInt; + myBindings[bindingNumber].currentSentl[tempElement] = tempInt; + myBindings[bindingNumber].currentElementSent[tempElement] = tempElement; + + } + + if (myBindings[bindingNumber].xplaneDataRefTypeID & xplmType_FloatArray) // process for datarefs of type float (array) + { + _parseFloat(&tempFloat, readBuffer, 3); + _parseInt(&tempElement, readBuffer, 4); // need error checking here + + if (myBindings[bindingNumber].scaleFlag) tempFloat = mapFloat(tempFloat, myBindings[bindingNumber].scaleFromLow, + myBindings[bindingNumber].scaleFromHigh, + myBindings[bindingNumber].scaleToLow, + myBindings[bindingNumber].scaleToHigh); + + XPLMSetDatavf(myBindings[bindingNumber].xplaneDataRefHandle, &tempFloat, tempElement, 1); + myBindings[bindingNumber].currentReceivedf[tempElement] = tempFloat; + myBindings[bindingNumber].currentSentf[tempElement] = tempFloat; + lastRefElementSent = tempElement; + } + + + break; + + } + + case XPLCMD_COMMANDSTART: + case XPLCMD_COMMANDEND: + case XPLCMD_COMMANDTRIGGER: + { + + + int commandNumber; + int triggerCount; + + _parseInt(&commandNumber, readBuffer, 2); + _parseInt(&triggerCount, readBuffer, 3); + + fprintf(errlog, "Command received for myCommands[%i]. cmdHandleCounter = %i. triggerCount: %i. readBuffer: %s\n", commandNumber, cmdHandleCounter, triggerCount, readBuffer); + + + if (commandNumber < 0 || commandNumber >= cmdHandleCounter) break; + + lastCmdAction = commandNumber; + + if (readBuffer[1] == XPLCMD_COMMANDTRIGGER) + { + + + // fprintf(errlog, "Device is sending Command %i %i times \n", commandNumber, triggerCount); + myCommands[commandNumber].accumulator += triggerCount-1; + + XPLMCommandOnce(myCommands[commandNumber].xplaneCommandHandle); + + + + + break; + } + + if (readBuffer[1] == XPLCMD_COMMANDSTART) + { + // fprintf(errlog, "Device is sending Command Start to derived commandNumber: %i\n", commandNumber); + XPLMCommandBegin(myCommands[commandNumber].xplaneCommandHandle); + } + + if (readBuffer[1] == XPLCMD_COMMANDEND) + { + // fprintf(errlog, "Device is sending Command End to derived commandNumber: %i\n", commandNumber); + //fprintf(errlog, "Device is sending Command End with packet: %s \n", strippedPacket); + XPLMCommandEnd(myCommands[commandNumber].xplaneCommandHandle); + } + + break; + } + + + case XPLCMD_PRINTDEBUG: + { + _parseString(lastDebugMessageReceived, readBuffer, 2, 80); + fprintf(errlog, "Device \"%s\" sent debug message: \"%s\"\n", deviceName, lastDebugMessageReceived); + + break; + } + + case XPLCMD_SPEAK: + { + _parseString(speechBuf, readBuffer, 2, 80); + XPLMSpeakString(&readBuffer[2]); + break; + } + + case XPLRESPONSE_NAME: + { + + _parseString(deviceName, readBuffer, 2, 80); + setActive(1); + + break; + } + + + case XPLCMD_FLIGHTLOOPPAUSE: + { + _flightLoopPause = 1; + break; + } + + case XPLCMD_FLIGHTLOOPRESUME: + { + _flightLoopPause = 0; + break; + } + + case XPLREQUEST_NOREQUESTS: + { + //RefsLoaded = 1; + //fprintf(errlog, " Device \"%s\" says it has no more dataRefs or commands to register!\n\n", deviceName); + break; + } + + case XPLCMD_RESET: + { + reloadDevices(); + break; + } + + default: + { + fprintf(errlog, "invalid command received\n"); + break; + } + + } +} + +int XPLDevice::_parseString(char *outBuffer, char *inBuffer, int parameter, int maxSize) // todo: Confirm 0 length strings ("") dont cause issues +{ + int cBeg; + int pos = 0; + int len; + + for (int i = 1; i < parameter; i++) + { + + while (inBuffer[pos] != ',' && inBuffer[pos] != NULL ) pos++; + pos++; + + } + + while (inBuffer[pos] != '\"' && inBuffer[pos] != NULL) pos++; + cBeg = ++pos; + + while (inBuffer[pos] != '\"' && inBuffer[pos] != NULL) pos++; + len = pos - cBeg; + if (len > maxSize) len = maxSize; + + + strncpy(outBuffer, (char*)&inBuffer[cBeg], len); + outBuffer[len] = 0; + //fprintf(errlog, "_parseString, pos: %i, cBeg: %i, deviceName: %s\n", pos, cBeg, target); + + return 0; +} + +int XPLDevice::_parseInt(int *outTarget, char *inBuffer, int parameter) +{ + int cBeg; + int pos = 0; + + for (int i = 1; i < parameter; i++) + { + + while (inBuffer[pos] != ',' && inBuffer[pos] != NULL) pos++; + pos++; + + } + cBeg = pos; + + while (inBuffer[pos] != ',' && inBuffer[pos] != NULL && inBuffer[pos] != XPL_PACKETTRAILER) pos++; + + char holdChar = inBuffer[pos]; + inBuffer[pos] = 0; + *outTarget = atoi((char*)&inBuffer[cBeg]); + +// fprintf(errlog, "outTarget: %i cBeg: %i pos: %i string: %s\n", *outTarget, cBeg, pos, (char*)&inBuffer[cBeg]); + + inBuffer[pos] = holdChar; + + + + return 0; + +} +int XPLDevice::_parseInt(long int* outTarget, char* inBuffer, int parameter) +{ + int cBeg; + int pos = 0; + + for (int i = 1; i < parameter; i++) + { + + while (inBuffer[pos] != ',' && inBuffer[pos] != NULL) pos++; + pos++; + + } + cBeg = pos; + + while (inBuffer[pos] != ',' && inBuffer[pos] != NULL && inBuffer[pos] != XPL_PACKETTRAILER) pos++; + + char holdChar = inBuffer[pos]; + inBuffer[pos] = 0; + *outTarget = atol((char*)&inBuffer[cBeg]); + + // fprintf(errlog, "outTarget: %i cBeg: %i pos: %i string: %s\n", *outTarget, cBeg, pos, (char*)&inBuffer[cBeg]); + + inBuffer[pos] = holdChar; + + + + return 0; + +} + +int XPLDevice::_parseFloat(float* outTarget, char* inBuffer, int parameter) +{ + int cBeg; + int pos = 0; + + for (int i = 1; i < parameter; i++) + { + + while (inBuffer[pos] != ',' && inBuffer[pos] != NULL) pos++; + pos++; + + } + cBeg = pos; + + while (inBuffer[pos] != ',' && inBuffer[pos] != NULL && inBuffer[pos] != XPL_PACKETTRAILER) pos++; + + char holdChar = inBuffer[pos]; + inBuffer[pos] = 0; + *outTarget = atof((char*)&inBuffer[cBeg]); + + // fprintf(errlog, "outTarget: %i cBeg: %i pos: %i string: %s\n", *outTarget, cBeg, pos, (char*)&inBuffer[cBeg]); + + inBuffer[pos] = holdChar; + + + + return 0; + +} + +int XPLDevice::_writePacket(char cmd, char* packet) +{ + //return 0; + char writeBuffer[XPLMAX_PACKETSIZE]; + snprintf(writeBuffer, XPLMAX_PACKETSIZE, "%c%c%s%c", XPL_PACKETHEADER, cmd, packet, XPL_PACKETTRAILER); + + + if (serialLogFile) fprintf(serialLogFile, "et: %5.0f tx port: %s length: %3.3zi packet: %s\n", elapsedTime, port->portName, strlen(writeBuffer), writeBuffer); + + + + if (!port->writeData(writeBuffer, strlen(writeBuffer))) + { + fprintf(errlog, "Problem occurred during write: %s.\n", writeBuffer); + return 0; + } + + packetsSent++; + + return 1; +} + + +int XPLDevice::_writePacketN(char cmd, char* packet, int packetSize) +{ + //return 0; + char writeBuffer[XPLMAX_PACKETSIZE]; + snprintf(writeBuffer, XPLMAX_PACKETSIZE, "%c%c,", XPL_PACKETHEADER, cmd); + memcpy((void*)&writeBuffer[3], packet, packetSize); + writeBuffer[packetSize + 2] = XPL_PACKETTRAILER; + writeBuffer[packetSize + 3] = 0; // terminate with null + + if (serialLogFile) + { + fprintf(serialLogFile, "et: %5.0f tx port: %s length: %3.3i packet: ",elapsedTime, port->portName, packetSize + 3); + for (int i = 0; i < packetSize + 3; i++) + { + if (isprint(writeBuffer[i])) fprintf(serialLogFile, "%c", writeBuffer[i]); + else fprintf(serialLogFile, "~"); + } + fprintf(serialLogFile, "\n"); + + } + + if (!port->writeData(writeBuffer, packetSize + 6)) + { + fprintf(errlog, "Problem occurred during write: %s.\n", writeBuffer); + return 0; + } + + packetsSent++; + + return 1; +} diff --git a/XPLPro_Plugin_Source/XPLDevice.h b/XPLPro_Plugin_Source/XPLDevice.h new file mode 100644 index 0000000..e94f498 --- /dev/null +++ b/XPLPro_Plugin_Source/XPLDevice.h @@ -0,0 +1,57 @@ +#pragma once +#include "SerialClass.h" +#include "XPLProCommon.h" + +class XPLDevice +{ +public: + + XPLDevice(int inReference); + ~XPLDevice(); + int _writePacket(char cmd, char* packet); + int _writePacketN(char cmd, char* packet, int packetSize); +// char* getDeviceName(void); +// int getDeviceType(void); +// char* getLastDebugMessageReceived(void); + int isActive(void); // returns true if device has communicated its name + void setActive(int activeFlag); + void processSerial(void); + + char readBuffer[XPLMAX_PACKETSIZE]; + + char lastDebugMessageReceived[80]; // what was last sent by the device as a debug string + float lastSendTime; // last time data update occurred + +// int deviceType; // XPLDirect = 1 XPLWizard = 2 + int boardType; // Type of arduino device, if XPLWizard + int RefsLoaded; // true if device has sent all dataref bindings it wants + char deviceName[80]; // name of device as returned from device + //char boardName[80]; // name of board type, implemented for XPLWizard Devices + + float minTimeBetweenFrames; // only implemented for dataref updates. + int bufferPosition; + + serialClass* port; // handle to open com port + + + +private: + + void _processPacket(void); + + int _parseString(char* outBuffer, char* inBuffer, int parameter, int maxSize); + int _parseInt(int* outTarget, char* inBuffer, int parameter); + int _parseInt(long int* outTarget, char* inBuffer, int parameter); + int _parseFloat(float* outTarget, char* inBuffer, int parameter); + + int _active; // true if device responds + int _referenceID; // possibly temporary to id ourselves exterally + + int _flightLoopPause; // while initializing datarefs and commands this can be true to stop flight loop cycle. Downside is, if it never becomes false... + + + + + + +}; diff --git a/XPLPro_Plugin_Source/XPLPro.sln b/XPLPro_Plugin_Source/XPLPro.sln new file mode 100644 index 0000000..5c063b9 --- /dev/null +++ b/XPLPro_Plugin_Source/XPLPro.sln @@ -0,0 +1,48 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30413.136 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "XPLProPlugin", "SimData.vcxproj", "{A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{36FDB778-95B3-4BB8-A122-80744B2DAA88}" + ProjectSection(SolutionItems) = preProject + ..\..\..\..\..\..\X-Plane 12\Resources\plugins\XPLPro\abbreviations.txt = ..\..\..\..\..\..\X-Plane 12\Resources\plugins\XPLPro\abbreviations.txt + ..\..\..\..\..\..\X-Plane 12\Log.txt = ..\..\..\..\..\..\X-Plane 12\Log.txt + ..\..\My Arduino Sketchbook\libraries\XPLPro\readme.txt = ..\..\My Arduino Sketchbook\libraries\XPLPro\readme.txt + ..\..\..\..\..\..\X-Plane 12\Resources\plugins\XPLPro\XPLPro.cfg = ..\..\..\..\..\..\X-Plane 12\Resources\plugins\XPLPro\XPLPro.cfg + ..\..\My Arduino Sketchbook\libraries\XPLPro\XPLPro.cpp = ..\..\My Arduino Sketchbook\libraries\XPLPro\XPLPro.cpp + ..\..\My Arduino Sketchbook\libraries\XPLPro\XPLPro.h = ..\..\My Arduino Sketchbook\libraries\XPLPro\XPLPro.h + ..\..\..\..\..\..\X-Plane 12\XPLProError.log = ..\..\..\..\..\..\X-Plane 12\XPLProError.log + ..\..\..\..\..\..\X-Plane 12\XPLProSerial.log = ..\..\..\..\..\..\X-Plane 12\XPLProSerial.log + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Debug|Win32.ActiveCfg = Release|x64 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Debug|Win32.Build.0 = Release|x64 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Debug|x64.ActiveCfg = Debug|x64 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Debug|x64.Build.0 = Debug|x64 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Debug|x86.ActiveCfg = Debug|Win32 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Release|Win32.ActiveCfg = Release|x64 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Release|Win32.Build.0 = Release|x64 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Release|x64.ActiveCfg = Release|x64 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Release|x64.Build.0 = Release|x64 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Release|x86.ActiveCfg = Release|Win32 + {A5C93EF2-9EEF-4A23-99ED-B1AC1F167F69}.Release|x86.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {751D5454-9CC8-4E22-98C6-9E3A1680E01F} + EndGlobalSection +EndGlobal diff --git a/XPLPro_Plugin_Source/XPLProCommon.h b/XPLPro_Plugin_Source/XPLProCommon.h new file mode 100644 index 0000000..75938ae --- /dev/null +++ b/XPLPro_Plugin_Source/XPLProCommon.h @@ -0,0 +1,70 @@ + + +#pragma once + +#define CFG_FILE "Resources\\plugins\\XPLPro\\XPLPro.cfg" +#define CFG_ABBREVIATIONS_FILE "Resources\\plugins\\XPLPro\\abbreviations.txt" + +#define ARDUINO_WAIT_TIME 2000 + +#define XPL_BAUDRATE 115200 +#define XPL_MILLIS_BETWEEN_FRAMES_DEFAULT 0 // for data sends +#define XPL_RETURN_TIME .05 // request next visit every .05 seconds or - for cycles +#define XPL_PACKETHEADER '[' // +#define XPL_PACKETTRAILER ']' + +#define XPL_MAXDATAREFS_PC 1000 +#define XPL_MAXCOMMANDS_PC 1000 + +#define XPLDEVICES_MAXDEVICES 30 + +#define XPLMAX_PACKETSIZE 200 +#define XPLMAX_ELEMENTS 10 +#define XPL_TIMEOUT_SECONDS 3 + +#define XPLRESPONSE_NAME 'n' +#define XPLRESPONSE_DATAREF 'D' // %3.3i%s dataref handle, dataref name +#define XPLRESPONSE_COMMAND 'C' // %3.3i%s command handle, command name +#define XPLRESPONSE_VERSION 'v' // %3.3i%u customer build ID, version +#define XPLCMD_PRINTDEBUG 'g' +#define XPLCMD_RESET 'z' +#define XPLCMD_SPEAK 's' +#define XPLCMD_SENDNAME 'N' +#define XPLCMD_FLIGHTLOOPPAUSE 'p' // stop flight loop while we register +#define XPLCMD_FLIGHTLOOPRESUME 'q' // +#define XPLREQUEST_REGISTERDATAREF 'b' // dataref name +#define XPLREQUEST_REGISTERCOMMAND 'm' // name of the command to register +#define XPLREQUEST_NOREQUESTS 'c' // nothing to request +#define XPLREQUEST_REFRESH 'd' // the plugin will call this once xplane is loaded in order to get fresh updates from arduino handles that write +#define XPLREQUEST_UPDATES 'r' // arduino is asking the plugin to update the specified dataref with rate and divider parameters +#define XPLREQUEST_UPDATESARRAY 't' +#define XPLREQUEST_SCALING 'u' // arduino requests the plugin apply scaling to the dataref values +#define XPLREQUEST_DATAREFVALUE 'e' + +#define XPLCMD_DATAREFUPDATEINT '1' +#define XPLCMD_DATAREFUPDATEFLOAT '2' +#define XPLCMD_DATAREFUPDATEINTARRAY '3' +#define XPLCMD_DATAREFUPDATEFLOATARRAY '4' +#define XPLCMD_DATAREFUPDATESTRING '9' + +#define XPLCMD_SENDREQUEST 'Q' + +#define XPLCMD_COMMANDSTART 'i' +#define XPLCMD_COMMANDEND 'j' +#define XPLCMD_COMMANDTRIGGER 'k' // command handle, number of triggers +#define XPLCMD_SENDVERSION 'v' // get current build version from arduino device + + +#define XPL_EXITING 'X' // xplane is closing + +#define XPLTYPE_XPLPRO 1 + + +#define XPL_READ 1 +#define XPL_WRITE 2 +#define XPL_READWRITE 3 + +#define XPL_DATATYPE_INT 1 +#define XPL_DATATYPE_FLOAT 2 +#define XPL_DATATYPE_STRING 3 + diff --git a/XPLPro_Plugin_Source/XPLProPlugin.cpp b/XPLPro_Plugin_Source/XPLProPlugin.cpp new file mode 100644 index 0000000..cab1c3c --- /dev/null +++ b/XPLPro_Plugin_Source/XPLProPlugin.cpp @@ -0,0 +1,363 @@ +/* + + + XPLPro - plugin for serial interface to Arduino + Created by Curiosity Workshop -- Michael Gerlicher, September 2020. + + +*/ + + + + +#include + + + +#define XPLM200 +#include "XPLProCommon.h" +#include "XPLMPlugin.h" +#include "XPLMDataAccess.h" +#include "XPLMDisplay.h" +#include "XPLMGraphics.h" +#include "XPLMMenus.h" + +#include "XPWidgets.h" +#include "XPStandardWidgets.h" + +#include "XPLMUtilities.h" +#include "XPLMProcessing.h" + +#include "XPLMCamera.h" +#include "XPUIGraphics.h" +#include "XPWidgetUtils.h" + + +#include "StatusWindow.h" + +#include "abbreviations.h" + +//#include "serialclass.h" + +#include "DataTransfer.h" +#include "Config.h" + +#include "XPLProPlugin.h" + +FILE* serialLogFile; // for serial data log +FILE* errlog; // Used for logging problems + +Config *XPLConfig; + +abbreviations gAbbreviations; + + +extern long int packetsSent; +extern long int packetsReceived; +extern int validPorts; + +long cycleCount = 0l; +float elapsedTime = 0; +int logSerial = false; + +int gClicked = 0; +XPLMMenuID myMenu; +int disengageMenuItemIndex; +int logSerialMenuItemIndex; + + + +XPLMCommandRef ResetCommand = NULL; + + + + + +PLUGIN_API int XPluginStart( + char * outName, + char * outSig, + char * outDesc) +{ + + int mySubMenuItem; + + char outFilePath[256]; + + + fopen_s(&errlog, "XPLProError.log", "w"); + if (!errlog) + { + XPLMDebugString("XPLPro: Unable to open error log file XPLCoreError.log\n"); + return 0; + } + setbuf(errlog, NULL); + +// Provide our plugin's profile to the plugin system. + strcpy(outName, "XPLPro"); + strcpy(outSig, "xplpro.arduino.cw"); + strcpy(outDesc, "Direct communications with Arduino infrastructure"); + + + fprintf(errlog, "Curiosity Workshop XPLPro interface version %u copyright 2007-2023. \n", XPL_VERSION ); + + fprintf(errlog, "To report problems, download updates and examples, suggest enhancements or get technical support:\r\n"); + fprintf(errlog, " discord: https://discord.gg/gzXetjEST4\n"); + fprintf(errlog, " patreon: www.patreon.com/curiosityworkshop\n"); + fprintf(errlog, " YouTube: youtube.com/channel/UCISdHdJIundC-OSVAEPzQIQ \n\n"); + + fprintf(errlog, "XPLPro interface Error log file begins now.\r\n"); + + XPLMGetPluginInfo( XPLMGetMyID(), NULL, outFilePath, NULL, NULL); + fprintf(errlog, "Plugin Path: %s\r\n", outFilePath); + + // first load configuration stuff + XPLConfig = new Config(CFG_FILE); + logSerial = XPLConfig->getSerialLogFlag(); + + if (logSerial) fprintf(errlog, "Serial logging enabled.\r\n"); else fprintf(errlog, "Serial logging disabled.\r\n"); + + + gAbbreviations.begin(); + + + + XPLMDebugString("XPLPro: Initializing Plug-in\n"); + + + + /* First we put a new menu item into the plugin menu. + * This menu item will contain a submenu for us. */ + mySubMenuItem = XPLMAppendMenuItem( + XPLMFindPluginsMenu(), /* Put in plugins menu */ + "XPLPro", /* Item Title */ + 0, /* Item Ref */ + 1); /* Force English */ + + /* Now create a submenu attached to our menu item. */ + myMenu = XPLMCreateMenu( + "XPLDirectB", + XPLMFindPluginsMenu(), + mySubMenuItem, /* Menu Item to attach to. */ + MyMenuHandlerCallback, /* The handler */ + 0); /* Handler Ref */ + + /* Append a few menu items to our submenu. */ + + XPLMAppendMenuItem(myMenu, "Status",(void *) "Status", 1); + disengageMenuItemIndex = XPLMAppendMenuItem(myMenu, "Engage Devices", (void *) "Engage Devices", 1); + logSerialMenuItemIndex = XPLMAppendMenuItem(myMenu, "Log Serial Data", (void*) "Log Serial Data", 1); + XPLMAppendMenuSeparator(myMenu); + + + if (logSerial) XPLMCheckMenuItem(myMenu, logSerialMenuItemIndex, xplm_Menu_Checked); + else XPLMCheckMenuItem(myMenu, logSerialMenuItemIndex, xplm_Menu_Unchecked); + + + XPLMRegisterFlightLoopCallback( // Setup timed processing + MyFlightLoopCallback, // Callback + -2.0, // Interval + NULL); // refcon not used. + + + ResetCommand = XPLMCreateCommand("XPLPro/ResetDevices", "Disengage / re-engage XPLPro Devices"); + XPLMRegisterCommandHandler(ResetCommand, // in Command name + ResetCommandHandler, // in Handler + 1, // Receive input before plugin windows. + (void*)0); // inRefcon. + + + if (logSerial) + { + fopen_s(&serialLogFile, "XPLProSerial.log", "w"); + if (serialLogFile) fprintf(serialLogFile, "Serial logger. Unprintable characters are represented by '~'\n"); + } + + XPLMDebugString("XPLPro: Plugin initialization complete.\n"); + + + + return 1; +} + + +// XPluginStop + +PLUGIN_API void XPluginStop(void) +{ +// cmpSelect.saveConfiguration(); +// cmpLEDEdit.saveConfiguration(); + + + disengageDevices(); + if (errlog) fprintf(errlog, "Ending plugin, cycle count: %u Packets transmitted: %u, Packets Received: %u\n", cycleCount, packetsSent, packetsReceived); + if (errlog) fclose(errlog); + + + if (serialLogFile) fclose(serialLogFile); + + +} + + +// XPluginDisable Handler. We do nothing in this plugin +PLUGIN_API void XPluginDisable(void) +{ +} + +//XpluginEnable handler. We do nothing in this plugin. +PLUGIN_API int XPluginEnable(void) +{ + return 1; +} + +// XPluginRecieveMessage Handler +PLUGIN_API void XPluginReceiveMessage( + XPLMPluginID inFromWho, + int inMessage, + void* inParam) +{ + char pluginName[256]; + + XPLMGetPluginInfo(inFromWho, pluginName, NULL, NULL, NULL); + + if (inMessage == XPLM_MSG_PLANE_UNLOADED) + { + fprintf(errlog, "%s says that the current plane was unloaded. I will disengage devices. \n", pluginName); + disengageDevices(); + XPLMSetMenuItemName(myMenu, disengageMenuItemIndex, "Engage Devices", 0); + + } + if (inMessage == 108) // 108 is supposed to = XPLM_MSG_LIVERY_LOADED + //if (inMessage == XPLM_MSG_PLANE_LOADED) + { + fprintf(errlog, "%s says that a plane was loaded. I will attempt to engage XPL/Direct devices. \n", pluginName); + engageDevices(); + if (validPorts) XPLMSetMenuItemName(myMenu, disengageMenuItemIndex, "Disengage Devices", 0); + } + +// fprintf(errlog, "Xplane sent me a message from: %s, message: %i\n", pluginName, inMessage); +} + + +/**************************************************************************************/ +/* MyMenuHandlerCallback-- Handle users request for calibration */ +/**************************************************************************************/ +void MyMenuHandlerCallback( + void* inMenuRef, + void* inItemRef) +{ + +// fprintf(errlog, "User selected inMenuRef: %i, inItemRef: %i\n", (int)(int *)inMenuRef, (int)(int *)inItemRef); + + + // Handle request for status window + if (!strcmp((const char*)inItemRef, "Status")) // menu 0, item 1, "Status" + { + if (!statusWindowActive() ) statusWindowCreate(); + } + + // Handle request for arduino device engagement/disengagement + if (!strcmp((const char*)inItemRef, "Engage Devices")) // menu 0, item 2, "disengage / re-engage" + { + if (validPorts) + { + fprintf(errlog, "User requested to disengage devices. \n"); + disengageDevices(); + + XPLMSetMenuItemName(myMenu, disengageMenuItemIndex, "Engage Devices", 0); + + } + else + { + fprintf(errlog, "User requested to re-engage devices. \n"); + + disengageDevices(); // just to make sure we are cleared + engageDevices(); + if (validPorts) XPLMSetMenuItemName(myMenu, disengageMenuItemIndex, "Disengage Devices", 0); + } + + } + + + // Handle request toggle for serial logging + if (!strcmp((const char*)inItemRef, "Log Serial Data")) // menu 0, item 1, "Log Serial Data" + { + if (logSerial) + { + fclose(serialLogFile); + logSerial = false; + XPLMCheckMenuItem(myMenu, logSerialMenuItemIndex, xplm_Menu_Unchecked); + XPLConfig->setSerialLogFlag(0); + } + else + { + fopen_s(&serialLogFile, "XPLProSerial.log", "w"); + + if (serialLogFile) + { + fprintf(serialLogFile, "Serial logger. Unprintable characters are represented by '~'\n"); + logSerial = true; + XPLMCheckMenuItem(myMenu, logSerialMenuItemIndex, xplm_Menu_Checked); + XPLConfig->setSerialLogFlag(1); + } + + } + } + +} + + + + +/**************************************************************************************/ +/* MyFlightLoopCallback -- Called by xplane every few flight loops */ +/**************************************************************************************/ +float MyFlightLoopCallback( + float inElapsedSinceLastCall, + float inElapsedTimeSinceLastFlightLoop, + int inCounter, + void* inRefcon) +{ + //return XPLDIRECT_RETURN_TIME; + //fprintf(errlog, "Time: %f \n", inElapsedSinceLastCall); + elapsedTime += inElapsedSinceLastCall; + + _processSerial(); + _updateDataRefs(0); + _updateCommands(); + + cycleCount++; + return (float)XPL_RETURN_TIME; +} + + + + +int widgetMessageDispatcher(XPWidgetMessage inMessage, XPWidgetID inWidget, intptr_t inParam1, intptr_t inParam2) +{ + // need to add for each dialog for now + + return 0; // always return 0 if we don't know what to do with the message + +} + +int ResetCommandHandler(XPLMCommandRef inCommand, + XPLMCommandPhase inPhase, + void* inRefcon) +{ + // Use this structure to have the command executed on button up only. + if (inPhase == xplm_CommandEnd) + { + + fprintf(errlog, "XPLPro/ResetDevices command received, I am complying. \n"); + + disengageDevices(); // just to make sure we are cleared + engageDevices(); + if (validPorts) XPLMSetMenuItemName(myMenu, disengageMenuItemIndex, "Disengage Devices", 0); + } + + // Return 1 to pass the command to plugin windows and X-Plane. + // Returning 0 disables further processing by X-Plane. + // In this case we might return 0 or 1 because X-Plane does not duplicate our command. + return 0; +} \ No newline at end of file diff --git a/XPLPro_Plugin_Source/XPLProPlugin.h b/XPLPro_Plugin_Source/XPLProPlugin.h new file mode 100644 index 0000000..9650a83 --- /dev/null +++ b/XPLPro_Plugin_Source/XPLProPlugin.h @@ -0,0 +1,17 @@ + +#pragma once + +#define XPL_VERSION 2302091 +#define XPLM200 + + + +float MyFlightLoopCallback(float inElapsedSinceLastCall, float inElapsedTimeSinceLastFlightLoop, int inCounter, void* inRefcon); + +static void MyMenuHandlerCallback( + void* inMenuRef, + void* inItemRef); + +int ResetCommandHandler(XPLMCommandRef inCommand, + XPLMCommandPhase inPhase, + void* inRefcon); diff --git a/XPLPro_Plugin_Source/abbreviations.cpp b/XPLPro_Plugin_Source/abbreviations.cpp new file mode 100644 index 0000000..4dad91f --- /dev/null +++ b/XPLPro_Plugin_Source/abbreviations.cpp @@ -0,0 +1,89 @@ + +#include +#include + +#include "XPLProCommon.h" +#include "abbreviations.h" + + +extern FILE* errlog; + +abbreviations::abbreviations() +{ + + + +} + + + +abbreviations::~abbreviations() +{ + + if (_abbFile) + { + fclose(_abbFile); + fprintf(errlog, "Abbreviation file closed.\n"); + } + + + +} + +int abbreviations::begin() +{ + + _abbFile = fopen(CFG_ABBREVIATIONS_FILE, "r"); + if (_abbFile) + { + fprintf(errlog, "Abbreviation file opened successfully. \n"); + return 1; + } + + fprintf(errlog, "** I was unable to open abbreviation.txt! This is not critical. \n"); + return -1; +} + +int abbreviations::convertString(char* inString) +{ + char inBuffer[200]; + char *retBuffer; + size_t inLength; + size_t startPos; + size_t endPos; + + if (!_abbFile) return -1; + + inLength = strlen(inString); + +//fprintf(errlog, "searching abbreviation file for: %s\n", inString); + rewind(_abbFile); + do + { + retBuffer = fgets(inBuffer, 200, _abbFile); + if (!strncmp(inBuffer, inString, inLength)) + { + if (inBuffer[inLength] != ' ' && inBuffer[inLength] != '=') continue; + + fprintf(errlog, "\n Abbreviations: converting: %s to: ", inString); + + startPos = inLength+1; + while ((!isgraph(inBuffer[startPos]) || inBuffer[startPos] == '=') && startPos < 100) startPos++; + endPos = startPos; + while (isgraph(inBuffer[endPos]) && endPos < 200) endPos++; + +//fprintf(errlog, "startpos: %i endpos: %i \n", startPos, endPos); + + strncpy(inString, &inBuffer[startPos], endPos - startPos); // dirty but it works + + fprintf(errlog, "%s... ", inString); + return 1; + + } +//fprintf(errlog, inBuffer); + + + } while (retBuffer != NULL); + + return -1; +} \ No newline at end of file diff --git a/XPLPro_Plugin_Source/abbreviations.h b/XPLPro_Plugin_Source/abbreviations.h new file mode 100644 index 0000000..90272a6 --- /dev/null +++ b/XPLPro_Plugin_Source/abbreviations.h @@ -0,0 +1,18 @@ +#pragma once +#include + +class abbreviations +{ + +public: + abbreviations(); + ~abbreviations(); + int begin(void); + int convertString(char* inString); + +private: + + FILE* _abbFile; + +}; + diff --git a/XPLPro_Plugin_Source/libconfig.h b/XPLPro_Plugin_Source/libconfig.h new file mode 100644 index 0000000..5e4eea3 --- /dev/null +++ b/XPLPro_Plugin_Source/libconfig.h @@ -0,0 +1,355 @@ +/* ---------------------------------------------------------------------------- + libconfig - A library for processing structured configuration files + Copyright (C) 2005-2018 Mark A Lindner + + This file is part of libconfig. + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License + as published by the Free Software Foundation; either version 2.1 of + the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with this library; if not, see + . + ---------------------------------------------------------------------------- +*/ + +#ifndef __libconfig_h +#define __libconfig_h + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) +#if defined(LIBCONFIG_STATIC) +#define LIBCONFIG_API +#elif defined(LIBCONFIG_EXPORTS) +#define LIBCONFIG_API __declspec(dllexport) +#else /* ! LIBCONFIG_EXPORTS */ +#define LIBCONFIG_API __declspec(dllimport) +#endif /* LIBCONFIG_STATIC */ +#else /* ! WIN32 */ +#define LIBCONFIG_API +#endif /* WIN32 */ + +#define LIBCONFIG_VER_MAJOR 1 +#define LIBCONFIG_VER_MINOR 7 +#define LIBCONFIG_VER_REVISION 0 + +#include + +#define CONFIG_TYPE_NONE 0 +#define CONFIG_TYPE_GROUP 1 +#define CONFIG_TYPE_INT 2 +#define CONFIG_TYPE_INT64 3 +#define CONFIG_TYPE_FLOAT 4 +#define CONFIG_TYPE_STRING 5 +#define CONFIG_TYPE_BOOL 6 +#define CONFIG_TYPE_ARRAY 7 +#define CONFIG_TYPE_LIST 8 + +#define CONFIG_FORMAT_DEFAULT 0 +#define CONFIG_FORMAT_HEX 1 + +#define CONFIG_OPTION_AUTOCONVERT 0x01 +#define CONFIG_OPTION_SEMICOLON_SEPARATORS 0x02 +#define CONFIG_OPTION_COLON_ASSIGNMENT_FOR_GROUPS 0x04 +#define CONFIG_OPTION_COLON_ASSIGNMENT_FOR_NON_GROUPS 0x08 +#define CONFIG_OPTION_OPEN_BRACE_ON_SEPARATE_LINE 0x10 +#define CONFIG_OPTION_ALLOW_SCIENTIFIC_NOTATION 0x20 +#define CONFIG_OPTION_FSYNC 0x40 +#define CONFIG_OPTION_ALLOW_OVERRIDES 0x80 + +#define CONFIG_TRUE (1) +#define CONFIG_FALSE (0) + +typedef union config_value_t +{ + int ival; + long long llval; + double fval; + char *sval; + struct config_list_t *list; +} config_value_t; + +typedef struct config_setting_t +{ + char *name; + short type; + short format; + config_value_t value; + struct config_setting_t *parent; + struct config_t *config; + void *hook; + unsigned int line; + const char *file; +} config_setting_t; + +typedef enum +{ + CONFIG_ERR_NONE = 0, + CONFIG_ERR_FILE_IO = 1, + CONFIG_ERR_PARSE = 2 +} config_error_t; + +typedef struct config_list_t +{ + unsigned int length; + config_setting_t **elements; +} config_list_t; + +typedef const char ** (*config_include_fn_t)(struct config_t *, + const char *, + const char *, + const char **); + +typedef struct config_t +{ + config_setting_t *root; + void (*destructor)(void *); + int options; + unsigned short tab_width; + unsigned short float_precision; + unsigned short default_format; + const char *include_dir; + config_include_fn_t include_fn; + const char *error_text; + const char *error_file; + int error_line; + config_error_t error_type; + const char **filenames; + void *hook; +} config_t; + +extern LIBCONFIG_API int config_read(config_t *config, FILE *stream); +extern LIBCONFIG_API void config_write(const config_t *config, FILE *stream); + +extern LIBCONFIG_API void config_set_default_format(config_t *config, + short format); + +extern LIBCONFIG_API void config_set_options(config_t *config, int options); +extern LIBCONFIG_API int config_get_options(const config_t *config); + +extern LIBCONFIG_API void config_set_option(config_t *config, int option, + int flag); +extern LIBCONFIG_API int config_get_option(const config_t *config, int option); + +extern LIBCONFIG_API int config_read_string(config_t *config, const char *str); + +extern LIBCONFIG_API int config_read_file(config_t *config, + const char *filename); +extern LIBCONFIG_API int config_write_file(config_t *config, + const char *filename); + +extern LIBCONFIG_API void config_set_destructor(config_t *config, + void (*destructor)(void *)); +extern LIBCONFIG_API void config_set_include_dir(config_t *config, + const char *include_dir); +extern LIBCONFIG_API void config_set_include_func(config_t *config, + config_include_fn_t func); + +extern LIBCONFIG_API void config_set_float_precision(config_t *config, + unsigned short digits); +extern LIBCONFIG_API unsigned short config_get_float_precision( + const config_t *config); + +extern LIBCONFIG_API void config_set_tab_width(config_t *config, + unsigned short width); +extern LIBCONFIG_API unsigned short config_get_tab_width( + const config_t *config); + +extern LIBCONFIG_API void config_set_hook(config_t *config, void *hook); + +#define config_get_hook(C) ((C)->hook) + +extern LIBCONFIG_API void config_init(config_t *config); +extern LIBCONFIG_API void config_destroy(config_t *config); +extern LIBCONFIG_API void config_clear(config_t *config); + +extern LIBCONFIG_API int config_setting_get_int( + const config_setting_t *setting); +extern LIBCONFIG_API long long config_setting_get_int64( + const config_setting_t *setting); +extern LIBCONFIG_API double config_setting_get_float( + const config_setting_t *setting); +extern LIBCONFIG_API int config_setting_get_bool( + const config_setting_t *setting); +extern LIBCONFIG_API const char *config_setting_get_string( + const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_lookup_int( + const config_setting_t *setting, const char *name, int *value); +extern LIBCONFIG_API int config_setting_lookup_int64( + const config_setting_t *setting, const char *name, long long *value); +extern LIBCONFIG_API int config_setting_lookup_float( + const config_setting_t *setting, const char *name, double *value); +extern LIBCONFIG_API int config_setting_lookup_bool( + const config_setting_t *setting, const char *name, int *value); +extern LIBCONFIG_API int config_setting_lookup_string( + const config_setting_t *setting, const char *name, const char **value); + +extern LIBCONFIG_API int config_setting_set_int(config_setting_t *setting, + int value); +extern LIBCONFIG_API int config_setting_set_int64(config_setting_t *setting, + long long value); +extern LIBCONFIG_API int config_setting_set_float(config_setting_t *setting, + double value); +extern LIBCONFIG_API int config_setting_set_bool(config_setting_t *setting, + int value); +extern LIBCONFIG_API int config_setting_set_string(config_setting_t *setting, + const char *value); + +extern LIBCONFIG_API int config_setting_set_format(config_setting_t *setting, + short format); +extern LIBCONFIG_API short config_setting_get_format( + const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_get_int_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API long long config_setting_get_int64_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API double config_setting_get_float_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API int config_setting_get_bool_elem( + const config_setting_t *setting, int idx); +extern LIBCONFIG_API const char *config_setting_get_string_elem( + const config_setting_t *setting, int idx); + +extern LIBCONFIG_API config_setting_t *config_setting_set_int_elem( + config_setting_t *setting, int idx, int value); +extern LIBCONFIG_API config_setting_t *config_setting_set_int64_elem( + config_setting_t *setting, int idx, long long value); +extern LIBCONFIG_API config_setting_t *config_setting_set_float_elem( + config_setting_t *setting, int idx, double value); +extern LIBCONFIG_API config_setting_t *config_setting_set_bool_elem( + config_setting_t *setting, int idx, int value); +extern LIBCONFIG_API config_setting_t *config_setting_set_string_elem( + config_setting_t *setting, int idx, const char *value); + +extern LIBCONFIG_API const char **config_default_include_func( + config_t *config, const char *include_dir, const char *path, + const char **error); + +extern LIBCONFIG_API int config_setting_is_scalar( + const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_is_aggregate( + const config_setting_t *setting); + +#define /* const char * */ config_get_include_dir(/* const config_t * */ C) \ + ((C)->include_dir) + +#define /* void */ config_set_auto_convert(/* config_t * */ C, F) \ + config_set_option((C), CONFIG_OPTION_AUTOCONVERT, (F)) +#define /* int */ config_get_auto_convert(/* const config_t * */ C) \ + config_get_option((C), CONFIG_OPTION_AUTOCONVERT) + +#define /* int */ config_setting_type(/* const config_setting_t * */ S) \ + ((S)->type) + +#define /* int */ config_setting_is_group(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_GROUP) +#define /* int */ config_setting_is_array(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_ARRAY) +#define /* int */ config_setting_is_list(/* const config_setting_t * */ S) \ + ((S)->type == CONFIG_TYPE_LIST) + +#define /* int */ config_setting_is_number(/* const config_setting_t * */ S) \ + (((S)->type == CONFIG_TYPE_INT) \ + || ((S)->type == CONFIG_TYPE_INT64) \ + || ((S)->type == CONFIG_TYPE_FLOAT)) + +#define /* const char * */ config_setting_name( \ + /* const config_setting_t * */ S) \ + ((S)->name) + +#define /* config_setting_t * */ config_setting_parent( \ + /* const config_setting_t * */ S) \ + ((S)->parent) + +#define /* int */ config_setting_is_root( \ + /* const config_setting_t * */ S) \ + ((S)->parent ? CONFIG_FALSE : CONFIG_TRUE) + +extern LIBCONFIG_API int config_setting_index(const config_setting_t *setting); + +extern LIBCONFIG_API int config_setting_length( + const config_setting_t *setting); +extern LIBCONFIG_API config_setting_t *config_setting_get_elem( + const config_setting_t *setting, unsigned int idx); + +extern LIBCONFIG_API config_setting_t *config_setting_get_member( + const config_setting_t *setting, const char *name); + +extern LIBCONFIG_API config_setting_t *config_setting_add( + config_setting_t *parent, const char *name, int type); +extern LIBCONFIG_API int config_setting_remove(config_setting_t *parent, + const char *name); +extern LIBCONFIG_API int config_setting_remove_elem(config_setting_t *parent, + unsigned int idx); +extern LIBCONFIG_API void config_setting_set_hook(config_setting_t *setting, + void *hook); + +#define config_setting_get_hook(S) ((S)->hook) + +extern LIBCONFIG_API config_setting_t *config_lookup(const config_t *config, + const char *path); +extern LIBCONFIG_API config_setting_t *config_setting_lookup( + config_setting_t *setting, const char *path); + +extern LIBCONFIG_API int config_lookup_int(const config_t *config, + const char *path, int *value); +extern LIBCONFIG_API int config_lookup_int64(const config_t *config, + const char *path, + long long *value); +extern LIBCONFIG_API int config_lookup_float(const config_t *config, + const char *path, double *value); +extern LIBCONFIG_API int config_lookup_bool(const config_t *config, + const char *path, int *value); +extern LIBCONFIG_API int config_lookup_string(const config_t *config, + const char *path, + const char **value); + +#define /* config_setting_t * */ config_root_setting( \ + /* const config_t * */ C) \ + ((C)->root) + +#define /* void */ config_set_default_format(/* config_t * */ C, \ + /* short */ F) \ + (C)->default_format = (F) + +#define /* short */ config_get_default_format(/* config_t * */ C) \ + ((C)->default_format) + +#define /* unsigned short */ config_setting_source_line( \ + /* const config_setting_t * */ S) \ + ((S)->line) + +#define /* const char */ config_setting_source_file( \ + /* const config_setting_t * */ S) \ + ((S)->file) + +#define /* const char * */ config_error_text(/* const config_t * */ C) \ + ((C)->error_text) + +#define /* const char * */ config_error_file(/* const config_t * */ C) \ + ((C)->error_file) + +#define /* int */ config_error_line(/* const config_t * */ C) \ + ((C)->error_line) + +#define /* config_error_t */ config_error_type(/* const config_t * */ C) \ + ((C)->error_type) + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __libconfig_h */ diff --git a/XPLPro_Plugin_Source/monitorwindow.h b/XPLPro_Plugin_Source/monitorwindow.h new file mode 100644 index 0000000..cc217f7 --- /dev/null +++ b/XPLPro_Plugin_Source/monitorwindow.h @@ -0,0 +1,11 @@ +#pragma once +#ifndef MONITORWINDOW_H_INCLUDED +#define MONITORWINDOW_H_INCLUDED + + + +PLUGIN_API int MonitorWindowStart(void); +void CreateTestWidgets(int , int , int , int ); + +#endif + diff --git a/XPLPro_Plugin_Source/serialclass.h b/XPLPro_Plugin_Source/serialclass.h new file mode 100644 index 0000000..25260ed --- /dev/null +++ b/XPLPro_Plugin_Source/serialclass.h @@ -0,0 +1,50 @@ +#pragma once + +#define XPL_MAX_SERIALPORTS + +#include +#include +#include + +class serialClass +{ +private: + //Serial comm handler + HANDLE hSerial = NULL; + //Connection status + bool connected = false; + //Get various information about the connection + COMSTAT status; + //Keep track of last error + DWORD errors; + + + + +public: + //Initialize Serial communication with the given COM port + serialClass(); + //Close the connection + ~serialClass(); + + int begin(int portNumber); + int shutDown(void); + int findAvailablePort(void); + + + //Read data in a buffer, if nbChar is greater than the + //maximum number of bytes available, it will return only the + //bytes available. The function return -1 when nothing could + //be read, the number of bytes actually read. + int readData(char* buffer, size_t nbChar); + //Writes data from a buffer through the Serial connection + //return true on success. + bool writeData(const char* buffer, size_t nbChar); + //Check if we are actually connected + bool IsConnected(void); + + char portName[20]; // port name + int valid; + +}; + From ac7e2c5299526dc0d9f786295189e50cd9787bd1 Mon Sep 17 00:00:00 2001 From: GioCC Date: Tue, 10 Oct 2023 14:43:30 +0200 Subject: [PATCH 05/13] Updated ReadMe --- README.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0ab50b0..9db456b 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,6 @@ -# XPLPro -XPLPro +# XPLPro Official - GCC +Fork of [XPLPro project by Michael Gerlicher](https://github.com/curiosity-workshop/XPLPro) + +Kept up to date (best effort) by _g.crocic \_at\_ gmail.com_ with changes published (usually on Discord), +occasionally with small corrections added From eaf6114fdd2c2457b1b2122b3c1314416849e05d Mon Sep 17 00:00:00 2001 From: GioCC Date: Mon, 8 Jan 2024 12:07:24 +0100 Subject: [PATCH 06/13] BETA Added string processing Added functions Xdtostrf (replaces 'dtostrf' lib fn for non-AVR), _receiveNSerial Mods introduced in Discord post https://discord.com/channels/1062448359434113166/1092591510752612362/1192209314857893909 --- XPLPro_Arduino/XPLPro.cpp | 63 ++++++++++------ XPLPro_Arduino/XPLPro.h | 5 +- XPLPro_Arduino/XPLProManual.odt | Bin 38988 -> 29197 bytes XPLPro_Arduino/readme.txt | 12 ++- XPLPro_Demo/XPLProStringDemo.ino | 126 +++++++++++++++++++++++++++++++ 5 files changed, 181 insertions(+), 25 deletions(-) create mode 100644 XPLPro_Demo/XPLProStringDemo.ino diff --git a/XPLPro_Arduino/XPLPro.cpp b/XPLPro_Arduino/XPLPro.cpp index 0495c0c..3b41454 100644 --- a/XPLPro_Arduino/XPLPro.cpp +++ b/XPLPro_Arduino/XPLPro.cpp @@ -142,7 +142,7 @@ void XPLPro::datarefWrite(int handle, float value) return; } char tBuf[20]; // todo: rewrite to eliminate this buffer. Write directly to _sendBuffer - dtostrf(value, 0, XPL_FLOATPRECISION, tBuf); + Xdtostrf(value, 0, XPL_FLOATPRECISION, tBuf); sprintf(_sendBuffer, "%c%c,%i,%s%c", XPL_PACKETHEADER, XPLCMD_DATAREFUPDATEFLOAT, @@ -159,7 +159,7 @@ void XPLPro::datarefWrite(int handle, float value, int arrayElement) return; } char tBuf[20]; // todo: rewrite to eliminate this buffer. Write directly to _sendBuffer - dtostrf(value, 0, XPL_FLOATPRECISION, tBuf); + Xdtostrf(value, 0, XPL_FLOATPRECISION, tBuf); sprintf(_sendBuffer, "%c%c,%i,%s,%i%c", XPL_PACKETHEADER, XPLCMD_DATAREFUPDATEFLOATARRAY, @@ -215,6 +215,13 @@ void XPLPro::_processSerial() _processPacket(); } +int XPLPro::_receiveNSerial(int inSize) +{ + if (inSize > XPLMAX_PACKETSIZE_RECEIVE) inSize = XPLMAX_PACKETSIZE_RECEIVE; + + return Serial.readBytes(_receiveBuffer, inSize); +} + void XPLPro::_processPacket() { @@ -223,7 +230,7 @@ void XPLPro::_processPacket() { return; } - // branch on receiverd command + // branch on received command switch (_receiveBuffer[1]) { // plane unloaded or XP exiting @@ -290,8 +297,14 @@ void XPLPro::_processPacket() _xplInboundHandler(&_inData); break; - // Todo: Still need to deal with inbound strings - // Todo: implement type within struct + case XPLCMD_DATAREFUPDATESTRING: + _parseInt(&_inData.handle, _receiveBuffer, 2); + _parseInt(&_inData.strLength, _receiveBuffer, 3); + _receiveNSerial(_inData.strLength); + _inData.inStr = _receiveBuffer; + + _xplInboundHandler(&_inData); + break; // obsolete? reserve for the time being... @@ -332,22 +345,6 @@ void XPLPro::_transmitPacket(void) } } -void XPLPro::_seekParm(const char* buf, int paramIdx, int& start, int &end) -{ - int pos = 0; - // search for the selected parameter - for (int i = 1; i < paramIdx; i++) { - while (buf[pos] != ',' && buf[pos] != 0) pos++; - if(buf[pos] != 0)pos++; // skip separator - } - // parameter starts here - start = pos; - // search for end of parameter - while (buf[pos] != ',' && buf[pos] != 0 && buf[pos] != XPL_PACKETTRAILER) pos++; - end = pos; -} - - int XPLPro::_parseString(char *outBuffer, char *inBuffer, int parameter, int maxSize) { // todo: Confirm 0 length strings ("") dont cause issues @@ -375,6 +372,22 @@ int XPLPro::_parseString(char *outBuffer, char *inBuffer, int parameter, int max return 0; } +void XPLPro::_seekParm(const char* buf, int paramIdx, int& start, int &end) +{ + int pos = 0; + // search for the selected parameter + for (int i = 1; i < paramIdx; i++) { + while (buf[pos] != ',' && buf[pos] != 0) pos++; + if(buf[pos] != 0)pos++; // skip separator + } + // parameter starts here + start = pos; + // search for end of parameter + while (buf[pos] != ',' && buf[pos] != 0 && buf[pos] != XPL_PACKETTRAILER) pos++; + end = pos; +} + + int XPLPro::_parseInt(int *outTarget, char *inBuffer, int parameter) { int cSt, cEnd; @@ -494,3 +507,11 @@ void XPLPro::setScaling(int handle, int inLow, int inHigh, int outLow, int outHi XPL_PACKETTRAILER); _transmitPacket(); } +// Re-creation of dtostrf for non-AVR boards +char* Xdtostrf(double val, signed char width, unsigned char prec, char* sout) +{ + char fmt[20]; + sprintf(fmt, "%%%d.%df", width, prec); + sprintf(sout, fmt, val); + return sout; +} \ No newline at end of file diff --git a/XPLPro_Arduino/XPLPro.h b/XPLPro_Arduino/XPLPro.h index b80b20d..d0bf612 100644 --- a/XPLPro_Arduino/XPLPro.h +++ b/XPLPro_Arduino/XPLPro.h @@ -37,7 +37,7 @@ #else // and off otherwise #define XPL_USE_PROGMEM 0 -#include // this is needed for non-AVR boards to include the dtostrf function +//#include // this is needed for non-AVR boards to include the dtostrf function #endif #endif @@ -109,6 +109,7 @@ struct inStruct // potentially 'class' int element; long inLong; float inFloat; + int strLength; // if string data, length of string data char* inStr; }; @@ -236,6 +237,7 @@ class XPLPro private: void _processSerial(); + int _receiveNSerial(int inSize); void _processPacket(); void _transmitPacket(); void _sendname(); @@ -246,6 +248,7 @@ class XPLPro int _parseInt(long *outTarget, char *inBuffer, int parameter); int _parseFloat(float *outTarget, char *inBuffer, int parameter); int _parseString(char *outBuffer, char *inBuffer, int parameter, int maxSize); + char* Xdtostrf(double val, signed char width, unsigned char prec, char* sout); Stream *_streamPtr; const char *_deviceName; diff --git a/XPLPro_Arduino/XPLProManual.odt b/XPLPro_Arduino/XPLProManual.odt index 741961da7bb7b31a9c86a157cf0cc4a6704086b8..f60870f16b19ec33def21c70da41db04a5184721 100644 GIT binary patch literal 29197 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 literal 38988 zcmb@s1CS`smoC`0ZQHhO+qP}nHg4OtZQH)xecQJ7{$^(;;?4f&?Yxbxh|0>W%5%<_ zC!?w|&-oOjfk99J03ZMWERt!I^hTLr$N>NV{yG2N0#wPNvSz|9eTSeo7F81~||L4}6T?}1Z|39Go$C`to zovF=#L8-ruLj*?)0PxTGk2h5;Ty2f)3@vS(>0SP#O6Oo_9;qNF4hw|^^|uSGq=bml z-|Hv<03ZOwKQnC3pN9?rK(it#BBP9(dt`hVvxY82^`f^gHWusVMVkdj6{l?Qe^9biEgzB@22Zwe;)t`=klO-ix)7Q8+NuBhh``1zipFnH2C|)7HDVu zUZ;W*ND79^^Mw|`B{qHm&H^s~5g@O&{|b6S!!rzn3pdOK$7hD`Ge`%Z&?D@onYI}Q ze`8A!>NZ`Y%LhGk<2Q?4z*_%tHUk$R9BfNrIHF8j|Ey?ybU=ys#@> zj*8L^Ov#XQUG4oF2GMXY3xsuaN^I+rK&=;QNLS*YH!LjGf$oFPNL#8OJ%&}WVr*uy zFF^}(ybq!s2a@|zqM?`TN>Na+7vobhn+-OJA#Rg!?5MVVEF2p7A}HBHqfbte*fU%x1vT zvyB6;0TkIbr1iY{fLkgsZejpEZ?Jzv2ZhLqS5F#Tx>JqAJt`(LTF$QE%IfcZf=g2_P9XTtCrh&7GT5Bo{pIYq2#GHv3?8Pl7k-(y*C zZRM)%T^IKC?U}zM(ss5%r?-Xk;Wk}0VfW~o37mD0*|9RLLxl|*@GKhJO7sTfqP@i& z{#h^WWKKDQ*=J(L>9&kH+1lD-W+VClxQR=q&C$+M5tcEtdEwicj7%q8GxW>6g5`$1 zNb((q6L%T^9`UEsH*+>OF1UM0>j7#sp^J;NHLa8LPZ`E!prqfuvc0+lsP~>g{=kzl z;KQnK+wxW*L3rGVEoaAqH+wMX0*}AC8kpr!o*L3iw7DYT%@}%4*byY4R}ug=9Sv<@ z=e(YUiMCCjBQ_HlhL*H%X3iM!@t&g|T^B1b8O^-8Ms+baSGtzJ6HA3PyA+D1&b@<+ zF6Io$Fvrj}eG$pf55LmgX6yrexLdW^-7;fW-A*U$ABWmODn#(1innv`$~v_i{fpEs ztn83b+00`t{^iB^De{#d?|SOxGx*EWTRqNqmuA`9+v(-Yw}%vs8{0b*H-P*Dx=ME% z@wc^cw7H$4y~+`AGU|$%RWD=QbxIROAhV$o)b3f|1$Pc@vJ(gN|NPTNovo573&k%s z66|*wPahKwzGT%Ra;BY<3_0AeJG+bK2$LK+$DWovzyS^sCM+>yHk0VlM1b{t7G!3` z!B*r5)Navt&d9mmKS_2h$VbPNp(|_}b#dvB3^AUvF-0(Ox^~(_{wxxpm?*0RRgB-{ zu7~f|+G^k}UmcA0#)DymurS-*COwY_)XF*@2$NX@hZIrTuAue%a%4H*=4!gt-H;*7 zLgJ5x&t!~C&fKem@ZODl(Vc-3S5aq;#@E0pcs+B_4!HqK&{TSzm}3e|Ba@LCV;@{S z^(Ez8X5dUg8}*?u&tjJ&up4jpT|Yw*cGKN2^vkQk3?^-(XHVQbj&)hEGZVgGycn`C zg-q~0R(Y@Kq)!*?VSZAU@NX9=1_B-oChVA^gXN8-tC4fELy>Ja07)&Tqj9jJUla!B3YSHMCc#rY?J&kuW{@`OzQ~Ig$ADszPSfJS z0~T=V#}s+*%jBG4NV@()kXBAM=>tz^5sVO#;Elw(SVEgFJ-av zPtXm<5&lDF2uYC@Sd_!@rCuB_!`z?_eXsxWC#S|vnTHK+i8x9D$OAZDN3tMjPGyq@ z8z2^d)w`sYHU@P#KcoBVtx=fYIL$+^qZ#iN`Q;E8fNOyxkKSUC+q`(h+&hV&M*GU( z)Qa6N2HLT9D;>&!(eE!hR6PO~ao zg{@$SunUBb8;U>?=P)}6>W1V_AvEjtwU$N!nQKOX#0wc-wR%IG#Xwz=i9U~>?ZP7=;XH}#4cwOe@a=}zIj65FQJ0XBUperjy(H8dJDxXI?#rZ zkgcr|mi2aHmrTbMYt9gPi726sf}3Q3+T&Z0S1&AQ3Lq+8>rVgg8EgTZJI-;>!)GSr z;Ag@asX?&eGf-Y3W;?WVnbr7cZ`a86@z&pmp?G?Em`_1b=zt);LQp(adRICdqvvF( zg_M9l#K)dT8jx}ieeakN?Dl!_6@7?8Mq1lvrdkd>s#0rGzMV+bVF)2P&FdxaDy#^& zBU(;e#2(5pRSoN6cWibMy53>yto&eg9lSIf>Ewr#xCQF4fak2(23`QF{x)OnTyn-7 z%U1CY!3&Wnv(L-pr8%v9BA#SVj+wmh8@gBkO}S5!is0-uH+a%J_Ku=4oa>{VkKIq* z;!K2js9B6ApJ9E2v}l&$@UVOfBche@!vaP$#&%-_)U7*{Qocx9qLL>3 zG463mKKdP>qWmqpopP4$k;rtfalajyBq1X&zLw!9%64*7kiV<-mw%u%$lFOln{mx} z-w$AQJOXy~8bFKSH2MVb2u<}D8U4$pfkJFRph*di1o47N`qN>m3pFo0LRT%>hVsBE znII*_hyToDMKEIgCc-rd1>t@K6J!hbt2&OA2=O&IQ`ze2c9h(=7Jq@T3{E)#XG9s^6#=BY5CSz`5oWqr z^U6$t5wbV^QrS-h7G=E6wh^fPS!U6MExyu`RUgn3CFG7<$b>wpnKDVeh&V~j%<%Fe z89=vrF<@Vy@N zAJ1GPan~2D)6|5}q|bLw6h!}WXm=c9aMs-!$m&O1sr<4NxELr_ira&{6@^>@kwDnu zs-kD)0?cm*~J=j&Jlx2hB2f=l}t)CkdeDF#Z*z!IbyXNAmyf*hu{*9DE_%0hOA< z`Z?C`2q-);nw1GdnY^IrX%BSL!XnvmF<_h1P<&YmI=i>^2z!H%!wK{K6pD1N>T9Uk zgS9qx^}=hVaQg~1O3h)wQ<3BNn*6;}P&)j}H&3A}F#|=T{F?5*I_mq?oD9?cTO`3} z3#U5^)O&C_`ioM(YTLr$_Sr~JG)?<+tsU3Hwa$2bO-}kcfyFP&C6Dnc!*~xy}a7y>%Uv(9ubY zmK>bb@=-^QO!d2(&E^a0Mp`yxJBsNun|`=-t`z=!)jzx`rUlQ(Gf#Yp0uu$qjQP(K-Amy-HFGVBt1t;CAbMOgAcj^vJJ{a{HsLSm=e7ng}50cj~nvjYm1oapqW0u2=MvKyiPeD=`B zD3+wU)NjeISktH)hahNhXI+lU1DI26HN3rpl)m?yeYMKQw8C0G`4;*U+_P#O05QkZ!6qu&NOB>^scXYRf zrDMeZ_yBaW4U)2YrB{d5k00zJyjj%H0iffZCq1cFL0^u)`#Hl|wLejDj6dUo_Xcw0 ztu`(QpAB({!Wvf~B$t8`>dXXZqrWpM-u6znGxL^65z!n)^#P>1>rpvV!1q!u{Zg4y zk&NKkXBtH*x345tFT`?1Of1aa zU7h-VjD6N=TUVf6A|-6cYFLI~ES}?%!rT8v%L~sE^VjpBV1(IWRnRCk?F=H*kLN;~ zH2MR9?sOMS<4|y&zO$gNSkj0JYlM2}Y_gT4z~sD_K2>GC2<1g4lm3>9`pRuG%^_J9 z>AjrLh`ShrNK86QLwPfa#{w(+rP1BxIcMu_^eMi)bAR+j!k&SGIWDDWW$|5nT@5#&;6?+-zsq#5tfdjfj;!3O4qF!fP*y9_RppNKp9$fwjQCN*#yTPufCtRO1^LNrMW z`23sBhXoY*0YUEi2iM&^x6xa0@pkC%SwR zJQ~-cgd(Ffr8rbka_@z3NBYAVPBvmJA|AC4v(fyjgG$5c73F-B3GmKEj9##^x3>o1>k z1L8pR(ktuCQWWapSXXIs4W4jQb4Zv@cb~PaPC%)AWl#|wSE}KAVIEx68Z4kIPZL{`l^i6gs9OciH6cs8JHiXa7DYu#8bRt3PncS+u=#q`r~k+)iolH zH9U48PZoQHBgJk}S5K$BZ6zyg@U-N-K$I zB1rZOF?EhJp6-hF9%L2c$f?jydL)$UqJ*i^c!<(8ZNd`W>fSMx*fx-Qykfm6wN~P^ zPL!Q!r@9-U9=}4j(U6l}E$O(sXva2JB9II$uhP&7*tH1mAK;UI!`0)NKkk0Ici1NQCWzZ?NZR`SAf)tRMoMl-R>o;U5?1X zg5C3s6MQ{%sqdkz&gW{5fek-Eo!<3ezM*XBF|qB`Tu1Ls1x?SIm2#|{=RV;xMLA3Q zCy3L+8;GD=O83EjD>WpJ&9xwK0WHNG6zGCJrL z=5Soo#+{%T)MmAq$pfrWz68bW?X)%c2Fxj%f1b|C$thA-RDX4>Gc_SPfmiPA3xrO{ zhu?&qld@w(a*p)-Sq%!kW9S6!Wl5*lA=*U#ZYAMkX+pO5+8eqk5Nh>`R?d+wkf!Ac zrJvTv?@-3>S~MNXjCZ4q;tMDA1JV~tL%LnnEFWt~H1CuSEs~z_>xkMzvt?Sw-9%7D z5;hj7%!ua7>hNM<(s@8%f82QM> z#eCrCsP$9ql`a=|Mf_`V-><|C&JS+{eigJJ<(0I|s-SY!z$L3=VivSW<0JZ?X^o#W zktH2wOZr0hYO&yZ*DHBz`=O%X*UAOqD~x18U$%yWt`u}U9GgQ=Um*p=_*#uMMu)?x zQSneLt9(Oqfg-c43#KVhOyV6#a_H3p`25j>i^(x9IXn9DD#s>h^rYZmN}QHSyAx>I ztXn4V78p6A$|hCV)jE3eV1r>qcNnxN_dhknQ5lFEL9VaGl5q8D69RF?Ob;yf?9Vq4SbWpWOr-TRBBadIv3JY24W0s zYTBwK#hE8c(JRZ`n6@z#^Hi#46!@xOYc=>nxzDY>*=EHS>k}8GntE)14gK1bjIWH7 zQe4@j>f%!b16+O+axJybk<=bg#eSBi_3Otr3FJ(ne_b7ICU4pojn?N9H7VxYAN0C3*nyAV%~wB$6_QYw~HuwW;D{*-3p` zCP1)}q<77?JmSjK_n~@gIj++dI!`XL4(!15CEIuH#P>z&Z^6k!AS`kXQkt4Tv}E|2 zNncx`(_%stt&6j_4nCYoXsaM*f)l|l>R8@U^5BqOudix)_Px0M2VjNqDi>PD zkXR7Z5i#zyxL9i`_<4)mvZW`YClS+)EB=GL2@w<9ipy!eNXjUVjJO)=y!y=eIPPM2 zg?5gncaU=GY&{l@Uv>=%5qFN~-$1qP|1(e>6AKQtwS2Baqp@)?s)*V=Sx6D5rL9kJ z8ENNIyV0(~hI%pl@(>(sxuxD~gInh{KC~zZcroFz8K#=NS+7Q3Th%BhMX?kq;W6k! zXVyTeFH1^Nz(AsKn~|h6?#<+VI8}iBjQKA1_G@UJ-T|StY0lO$u$~+b@Fh~YLwADP z(U4-={#kf6`FYKHjG}dng!!sMzcemAiu@X806`I0GD-YWTOE1WD48=X<`lBORMJ+X zs%aW(dQ@7|{ZiR&b3wu)&?pztt3MD-01DMYcf4P77xOq>2#!lcoAM9FAz>Hx>d6+u z^W(AEqpvcdSB3T{S6Su#8hOjJ21_lbl!F9r-LG6PefR+g!aksF4yz!IX|H(FqYlS) zmWml`*Yiu8Z%b8p>Dbl#*$YRZ2UztYj8Ov#A2(?4QKNbQ%9wQ)VS$c! z&%PUHtx;F;s^2cF@=;3&USdftx8p%tjotH9LGAqc%s~{O=$~#_tA<7b;gIBaElQMM zL!zM~6e5lMD}d-e5ym3^)p4+UCC!Co8)(lYCN5fsIa+l{XkbBE+Gz8MwQ?L><09d; zWD3kiO;E@q#u9hz0VrE6NlVb2uqEauWSpuK_a0BvcSBY$@7r*wz+74!lA%pOFro7c zc|=d&84LJTMt_%OR-k;Vb8a(0(<46eJuhgWL3D!RSh;`dv@D=p-Nr)Ij7P+NRLQ!O z&Q(-kVlbAiu#}J5V*=*RDTHKFsaWBmxfkovq5yG;a!BAB4+}~a0^*WDF<%>W9>>ld zYG+aF&EQsX^9Eg!$V{CkMmlAs!%p!^L^~2HwdWhPtja@~^)td+gvd6moYcg@<+l{} z_B<{-d{ikGV=csH=%`RZ#5`&r&GAb`EhjY>7zGG;6H*lI#a1B62X(>?3er?Hj+t4H ztAWM?tu-w(eF)7-7b`i)&6y>GI@3}!e?Y==RAoC<3Yn8-EHoiq=@|3jII9HSb%zGy z+=jH)AL;of{o!SytnlQhpHAzQ1kLW}6}3`Qb5J4YTj+Qa2zGqibtO05tu+S-ozz5N z!Lw%7$08E%e8_BRsTB}MfwX2T3rtsdXj5I%VDz6;SB1lKQlGoLTAQ&~`@`^kl30hs zlIKk}prEBdE%z!4@xrYYR}1Z}wSZM&>|_`9xPe>p%xM*?Da}vQ%z)Ukz@|X zKfQc8Mz@zjk`987Pe-Ge_`1I8DTb#}L3J1yT?4Xi+9LZJ3T<2(7f_F7mmZXB%0YI{ zl#jjMo?<7Mov)hA)xF;|y<{;jq+t1LruUGTPf;-y&%|GyU?&uYJi8dg^%Um>(+IiPdS;JL-$}Znku9OhKbT2{w;~@( zxmA?qTWFL$MV>gaH5BAT%H_PM&gT(n&K;s0x6)%tL9G(|8=?9RLhYM$qYVd8?zsc57C*0a+ zv!ekRAT#wm{Qg;k{>$pM3((8i6f?lxHacLPJs|g z5%BY#e_};t=<}}I+)RI-f(J5oI-OSIuUyo_x1zS5qvJC-IjcXs@%D2d{u>9O#N&jE zX4+4c?PYUXNlzBLK~YzyT%6Jq-+EP7x4CWTXiy2>&JJMtRUnWdPlM4nu`bGYAB zD0N-r)g)fH7x!CRsL2I~N;>mMCuW`=QhY4G962N0b;cXjsn!L() zU1L@!Ux154bX(o69@ZCgQesJ?i*Mv3R~sv7jl0%7erVP1Ep(bV85Ct=nU?7EnS$uS zuG9@Boha%RHE zE-&;y=D*GTz6;j+Qf+@W^ZgF5KlHw{`(9t!`Cbp%d+ow)J)fcdU!S_J@pe3(Gx`0# zzxZD(y|07(Ke=z?)PrAuUQ2rPy{Bfg{hlND;J!}tJ#+t|H?nI{v&NT z2*kyJPDa!0;GyDAY;7=s0zfzfuS*KgJ(VI%4R3Vda3#wWD!d9l@1$wsLAP6cp*8=9=5NDKrr-cIQao3nAi7cuHG$zZ zzzC`^6swT|S3{Q-WpPPdMK^MIiQ;ntHYyG_au`)CA#09tQ(g&GNC_FGW$=t+lX5uB zD$op88q*OepjaosQ{an?l!&3{Uz(FTC?B=w#OI%(SrUFdL`9nAF&M#WJ zt_l-~RIoyJOQ<+q_XJp$5KjmFIcaoX80y-pPi_wYF;S^AXSv`x&|Y-Z9C;|Ssemnx zbTX3%B>%5Gun)4QICuZcB78q=pR*UgSKR#1yPtc!fZ$yA?~)#Q{ukt%AMd)au+zS; zo_wDJcK+8I|EIa$i{KyM``f8~X#Ahcw$I$YufewO&3L}AyS}@E1#P{b7W3ZEH2BZ^ zZ*c!>`0w9E@O-z8_?up5-u~ZBFMdnzyx+oe-#h-_dwlOV-^biP2l3x$Yx^VaLjy~F zcaKZRT09)ttAYbzHTmPlkPvLvk-}mgR?8qC>MgRM3K!5vlF;x1d?{@Rg2LIca`uFS2 zU{hOO*IUbt=WkmZte^gkCEFn1sAK z{4aQW!@9k%Km6V=MNVVzpNAL2(dyr<9>?;&VER0-RL}mGSFSz&@63M*T|Cc_8}Fpw z(f;jPu|21|=@ICA_f7%nKjhDc_FDW5;m7;!{}XPY7oI*RMobZf7TNdv?V>1V9gVZZ zyazWWy*BHR90@R8Hj?VpB=s9j)H_SuINGJmg*Mq*U6-u&MWQY))6kP4XMFsOBVRa0 zlByp=s4VFiXyatOzDo)nlB6fgh!ek$c+^O6VUQW8&?Qk(NlIa;y0%SZ@I>W(n&LiPbb4Sk;0eXA5R}Uo6SIvEzfhC0Vlltkm`G39z7RPmL*lcUrjEF5=+Syo;=BN zc4eY?k3@<95+I88ImaQ7=0^j}kc?D2Bh)g3xxN_6OX$!Nej_x*dA9_~R?cny>2^@pN@0xX z02S$e+ANzTqB*^5X#1#SO33^kP4+TP#jpDd#)2#w=d90g;s!uCk5yG3c=^SaIGRCC zG~!iQW*J2*#n4ya<_{E_TUfG1=T%?bxsg6n%EN{`6*BVbQ!vj@B5cK2XGKfNc)1d9g3r3nwJ$HP)niL_Z30a$Ca+Foe#{PPck!~o zxYfEezfM5sZ|ZX%ZS~h_4qS2Q>ni>4zCzn0Wo3Y)c2-Vb{H&`D-1=MNJ_G-cgwhoB zA7Mf;s&7;OkI$}Nk{(wLaO-(zy%OdqCNYfY`8jh*u*TieN<=CZiUh>DbvV^8c`mW@ znsW!VW(i6HTM)sj4Lv`$4M_ufpb>oE1RS)@L(GCx;sOMJPSLv~zd+q5<0QCW{G<}S zZ?a~DJuOabxCS+wqlHqZaF=#R$XH*wTMynP!kcvsz1n4-4nK<^P&@%VpFaR zTOEAVL3mq=_KZ@#ts~4JQ9GmWNc- zN2xiI_rI-xWE;iXL17b&^6shK^xdjTPYm&%&8Ouj=r^3@+=B@qlYWU%8cWlqle*>i z=3cnNW!!jdMGtv*JOyJ+!gw%e4IS)^~Qw>AKV+$J2eG_ zTkgaTqWEbsaHWh@z7(gC9ykscCyWt7xAVyD98sJUV7lrQ^Od%!M9Y}_9UqA3;N;$K zHJ=+4>talSt*Db79$L^FE>#96qGf2|@WoWZ^``pyVgRlMXOtLOqPO)z*vnZRvBbt_ z&z!kzX0&1}GFfeY`SnTmyoK%L(9I&{m-Dnu_{K#~lgwP!V>AB*l$(Q?Y64pVAs2Ji;;=XNdGDJr`wxzC4{W3 z4Q+<5c0xu}=PNCwi;FL$*rS3|0F&Bs)vA$G_N7yhXHSwxPP{J`xV9s4&%8Ooi4S5b z1xtm30yoACq7W#v!|si!5z_wal;A+vhgMW8iGmklRitl-cMon+XzH|6IId zHh4rK={yQk#VwPNmV9HI1NQCZJfhNgLqNK;mgwTt#MH#s=C2PuT zmmwrU6`v`6jraQf{?Yo_>E2A*chom$`5OkiD-Sdn!UOVpL;-X#pVozqUH*a3IdrVr z8cnLpq>#UnBS{}MLPdB+D+Af`f*23TxIgK)ibRL)4!a@+asEUSE41zw8l}=Ok?TMK z>vCrl5LzwoE0S*L5V==xs;{gDkpy*{%@xe}q=?n#O@C6QH2QEi zy=ulp3i!*$Qi(&dgxJvXd!+Bw$fhst0`KH*t*Aq8Dy96c81KxsSEE{N#D471N!!%O@|%Ww$blb15cO;cKcU*POvf$m0a1f_Bt1wJ8Cfd zXxh)6I6oVY8%IFgQP=Fm+PgU1*@tpL{T@j`df{%jrT4W7=XyZ(03R=DZokvXZoj`_ zx_|1Qb@{%6v)XnxquXyRqNp=^EwoE=otOHracAE=DBq0V8XAYMY6Go}&s)R$TSz^< z5oUVzb%l~&h3JsF+kQw>52ggtpTEwjtxZpOrY;Xm-1@jCPHoKR_8mnrpOp*W*20nV z6@7tDoQe6R2RwG*^C?<>3a3>yaxl=eB*r5?ZKql8Yz7KPPh zeS-3JPS%bj4viEQax-C6HKB7@#;agD#?9 zi_;v~eHV}p0$Xn9rm{lU+T*@x5D0faIVxJdh1(8d+e0Rr=TjW&ZY@(B@X+|+KdU+X zhJykMw5g^c*mTeh{rUtmd(Ke+vG2T4nAMA$k_-iZJ35g<3%dUiUwT(5KI-gbN#{B)(@cz*an~O!6a2g^Kw1n_KbfC6K3uf0C0jM&0Wr=gtQ8a%?x)hN@3!q)~GcQ zy9dQvd~_bsUWqi#EzZt%o^St^4uX3M!k6!$f3Z*S;G3saiM(|{!TQutUR)P>nY{E~ zO!q7yTNJi-XSFYR)u#WGhhI{!AQ+$i0+2U*D%&Me zcv?DY_!~ICLmfZB#6e;btYz@<7BLQgMD0&5@yv6?cS%@T4??F@X-VPDr{UvIIv)nW8_jT)#G z;`C9e;F+-+u$zDH5WBr)4ce&|f%m9|=W*~gSUc=@Hr+p<2JV77c08I`s)o7@`;~7E z2(J&lJ|mSQ9!Dw(3thbzUG&z?+!y`pXT3xaBhk$U80+z$v8*?UE zj7Inlhq?*AtQYKUd$iZ5-Q;dn`W~Wz+EcA=Dx^F&kx#~7!E-{pKGe6Ha-pb~vD7ZD zk9pq=W-fX?wI!=xrGtaBqZPTEXNP|ynaOF;letcFQpC_QwnRK|Fs&TPO5&N%;*iilc@j93pb|nb=4xCgY1pBJ({PNVt@@4Nxq`3geMQnUpUTPE;hCPTt1RU0e=F&#w1W13W^U3G$3?xn~aW|Gb;1ZX)*2Fd8sWtTGo{rqAl2zq3T@)SD+hM*b|a5_vu z=ow(W07rV-oVOqyW#4HJfCXObG6+pq+F`^05Z0Axw{?co(xt2X*`HlXG;KiAGn%Le zDm8z)d$O&`sBUb2qZ-3W=TRigJS(L?k(0?ch74+~{Uh=NN{eDv(Aw z0VzUDId4iBN-w5J5DRrOITaj-wu5)+2=Dc=Rrgc$3Y78o_dB*WkCm!x5^-&d@^$R1 zdgWkjalR_2&rGRv;SIUpDKvj(mvfE4l5kB54;b&@D%v3-pl|R??MYLgHSL5D6ne)o zWjXbTT8}zECeHqDBXY^{U8pa@Mhv#cZj41HG@Smu89SV|%N%R${llO}tjv3PR88v# zT`J^uMa*o<1=?$1$`8RVEAYs2^K}Hb%(Tk>wwq6dKNtG6(ACe+kf#g+nAcETiI< z!bsu4Pj*>n{syKGSTvilZMNoubGE8Au&Y9=Fd}lYPa=oYMJE@W*Hg1QHN)eUU zO;L4|yJ~VI^nJt5b&h_v^Xhu*t4fMh&-hl`VIDyv%m~Drj1nzG90I2K3;?Ip58fn7 zA{yLL>Ki=(CC9IyDd4=G{&q{LqGXal#b-1JQl9{-7aIjs(4tDzxU&DD>s+j@(ylpo zwGbPyxVsQ**08Rr66;E@uB#F&H&^wjyR1jzXXb+V<7w-90k}NO=*sA-SjnzohSw&N zGM%UY^-XRvX3E#2$Q^~gh6GyGLKHw=YkbUxNWc&hGUw}fvbdRE#^j4H2Cn)B$+*dzPXEVDtz*`!f@@ocWbV0HHgC7_c@%vD^vbHX?5l;ob$v z|L}ycNPK+Qu03@G4GvK_1J3|l3#$Yh>vkMqK|ao@0k+ZC7h^gF@dky>5zyStGl_|T zRaDdxj!YEtn1r!-#=sMb6xfW_5}9nr+A#ZHNk;UQY|q85yCC-VPyTF;4XWg?-o_6Klm!C`I`^>~fOOY5|<{>-cp! zc+?Iu#qvdES<6MJMmJZXt0p(`;l11TrOU1E$$O-%0}XI~e_EK-Qv%~aB~7t!OAkSL z>iRKlc-i*x<7x;AW8plNK+fBok&`x<18~S?H?PGHA7f$fq{M&U;0W2lEHnBHd!6eI zwz@6Ad{72{8s1x>GrXn)onoDN#lAlw_D8I&rkZ<%g!%ZI1BKt*XXOqiuy5aV9Gl8K z+)kv@F;uEh?raP|dypa&0Z1S{BfQ1-nvy-lFWXb3oVf$Xm3?#-gGI&MNBOqB7epP^ zl#d2~On?Z1<%ot)9`eUzu@iFO=8(tAe^i-@Aoj?!x3qGr*2AF*5q?VDC_(X7vVAV| z_lkmQ3qdxK2nclq?65i>8`Ogn<9#atoGBWz!}5U$s`AOsImNcpK$>w!mJ5I%+&Tb@ z$)t%KkNjusDH=i#GWc zT)N1Hg^eWN0c5}pgr9*g5X=Y)FHHy$bgHPx^*UG(xV&LuWj=MdW`aow6ze`&VK8K- zC*f+)x5i_f9T2w(@ooAb>%4KsY71JUBvkW)Pj{m;6Yj&b5YW1KbHEV{HEocZMJrKx zc~KcY#(NP8zF7d&K3o8N^M}!~8$Bl--%g93CH*5VOI=F05?gt>O(mF^{OIifSs*^m zE}#JQX5xUim>ksoIHS{y$7EqQsgNxCG%g2BEoi+R+1Cc3R#6Plkt_qq__jTw6;bPj zuL3SI;GXCgQUfAdp+slFZ^-e5?15DQC#5p_9H4u&c42Wf;$>0ez5EFul=y`pg#jt{9G~-UtdtnB!4AsAe7LTc$*AIA3 zek=dkWJNutXiJjY-LPKv5wMg|g{q2) zVrq3DAxP2lZ7=Rt)pyGnY6e)cPC5>G!)&`u12h{Z;{wcrt%xggi`Q0Ken+VMwg=u9 z({4FH*OKY#0bb@9uT>?BCIy$V)#O;(mWLq3WJ6UCOfKI-GJ@DX=?sdx5Fjc@8`RJ3 z0cdAli~_2hIATvF$Uqf;#DCrIoM!s@8pWahv#94M2wpG{I0A~B+dMTcg0Icb#AqST z?@1WWm62IikGD1gs_Jgy5lcv$Lfnuu#L5QqrZQtI@NziqeXxlA^c%c+aJrVDb)bRi zG^TP^z@}u315tDlC7Apioh4CK`3VGDBdHz}RuRXVhWFeJai4G)h^MMXXv9_*eu7%j z`87pV_}R_=DARxKS}kwuR1Vc%S|MQGLmdBQ1PX_{9tMh|UQK8!uw`Ebo`#sqT#23tIXD^|ZN~2t!wv^^<*5MRP#f0{F&-+@G;3SZZ9hf zPw@BqR50O3lyhLEc1oO1%`TE7Bu^@hBrniQeDiVo74vF>c-*$@9wT2jorQer>)h20 zSc*A$_ITeD6cfG$+I&=n>Dh3N67PlckF>{IUG^Q5nUBvUlBI9m)3(ZRUn{=P)ytZ7 zcVv^T*_S)5S~`Jlu21^ig zzg9NikLEN}{8;xr5GB9tKr@H63Rw;Kgfw*>2Apqw06t46s2PrMrprQ5O^Kz=wigCL0~CCyA}N8cpb-4~kQEm)_-T78i8kN2Bro;wAo7v(#DSmpO@V4Blz8{T|Ofv*yiy;0l;@$!{lBQ`7 z)Jj@OD`~~d(u$dxnVFfHnOQ4lW>_&ZGcz-dn3-ADzTa=(IsAW)bJ%y+5!Id9(@|A3 z(_LAa_2kppzGsfX?)%b)MNaeQxNMo7b4?u5kHvEouPFDkn1qcRK9)<;3z5hQC)21Z z?IC600v0wiFp6v{mjT)uY~?R-y%D6PP;lojsBP7Ws9Yh1T7 zC*eF3OrJIH$Dbg7i9NC*JgaBEcuLTH{wuM^f5sOA{S^td)N`|Oa-=fQGcYwWFw`|9 zRh{bY-Xi`q17@PT87`rIWYzZ-B%qH5MW<>Q3kNBufsP7c@ch~ z%1Nx_F9pG-^Z;DxS-quEw7M@9aq@wLNr$^Lj3tMJa zIB`d9KatI1l}x^!k8sQEVkpuN-ey+Ce^`KIa65b!e6s7+dqBmCwY2AV|e2t!Zc?VON3Xi29+{!1f zR>0ew5F<@(Je7a!?n-J!Z#lzDm+EKpnLawNRgQBmaZ4qtLSaL-3@l=5FLl5sRZ)0%iHETF=PdGkTF;*i+ zbuqKBlOMV_p7fv(n>R}$&sFp74rvff6d#zd@YI$Ze`YK=-jBbPJ8ZtGt4wchZG0Z< zHd7|ldglJq3bVspOD`3Pjm*|q3BEtz7~u)IfT?(abws6rK5o^!p#G=g=4aYMI-h(M zf=Lqdn$msZFY-+Z)DqWY0v{Fuh2)Sz8tv(Cly{1`1TrX&Fb3-cKk>UTsik(YuO^EbXo&(I9R=@=d}HcMsg2YerE&*VJ8%N7%A# zk~msDBW}5_U%~6wKI$NoqivYmUY<=9Gv$KF$2ALU-xWj!S3GV&`A?$eC@OfI*W|a% ze9tra%20sv&lWz&&lsQ-8$V?+VJGkW**iXLEr@I;z*ed zVt2`jK9gXI)Gw$izb+U>@_7H47tWK zjJ}Y2741B3ky+1p?O1YgUs{rZ3@-VItjRWlJL>{9NSl>hy+jw*>>8>>{ZL!Y9*yQ) zi05*D=Nbv$(^<%^0&s7+AKdlPd#L{bXDAsdj)MMET^y@lCwW0B(uAJI6`dY?iJ9wC zq24n1c`w@9|60cMtRcPh`PzdHm2JHwC14ENo(dzaW6VTI_1S1iJRB}&$Sq|io{7|P zXQUiLVCxl)gL3%T0FxB90gb>n?TI zCD(v$)49~<pF`#9V5%$o5Q6^0arq;Ty9S}u?(!Wc-Jd@uK{&J*&u#O?X z;^S(72$P(%eZvyi7plwdzf(%zeiB1R$ndG@edJ?!i7Eie>bHAIX&| zPCOumIK{5_g>JTCSvGA%kQTBbe3B2ucvVr%)E8YAQE@*;+zXpHXQOY6sv4CN(|S1t z_GO}it1gM(lZzivQVUDE@_#0xQndnpc?s-r$D>YDI($kyn?1U@@?_we6*+T1y&w-q zZ@U*x)@;8B_Mwf1zYpjK;PU-IsqUZJg2Y8S3R(f4WOC$c@W?CsH2$bTxJ zd7x=uZ_?*Wh;XNe1KF_lXlCxzEMnP5E-B@J?Q%YP#ceJdt6n7y6)s5Od0jmh-s&$n zOhA*GAae!ur(*7u`LLvp{i$Y8_4bB~<*Wp^sPeSudVTcGPX2d(J7n>zN%9)J!xsJ>mvNa@!l-a8UO%6O59aZTtySxXp zpGfuOi##$b2F}dN@zEpOnNc7oWx`nNufz!;b|m6;+rmqR;HVdR z0@wSrVuL5Ph{UCsfZ?1Wxuvf4vXKEMKa+%J?&tAs+74S~r_eb-D}Q1C3h#`p!pb8W zQXPOj^G5N5qc@m@oa&uhdO-U3V~1xjPUj1{)d`G~ms{VOiRQ|{LO3G@K;i>8a4PQ? zd(4jL@(tICg_)ci-9oBWV66yxGY^WINv%~eYAdgVN|dRU7MIx%X97vRK8kh(tm4PU zrq@&UsOu*qz44(b8+Y+fxcSNsfvT>NOq!0LYQxo^^rBDN$b6f>sxN&W!r*LZiLwtI z`yRRdb&kBp1~-zLDfq#q3)yTkpHJNd#Ok^zXE{9|cwPaIo4bD9hf_yO5?$3ziNI77 zE~XWES@ob*CWY18L9f;wFX}fIT5;Y}s@L7E7Y)OUeYzSLqzCSWo3A5R_~6+{CCwJB z_w3DEjp{lkHf^{KNpotrLn0wQ5*0PKJ7l#NbD@Z?Rk<2 zBaijay9zZ$HdGpE8RAhk^B8E=HMjQf#Lcrdf4(z;y^ zcJX|&f9zV(MBE~~x)3mDO-8qe=iYAZ2_)LAc^`I19(JniCicDCHv44D!?0x4@w|Ek z+HziUK`5-eA1~}_L4T~gYq=Hi%{Dv^+;1g_g^!1aRMgcQ;mXn!8uahnn3baLr#xal za*HW0Z|$OreB@;~K<{JYH2s7XW%zh1n2-?Ud`xjr-MhZs>Cf~D7;d0=L9jFQqI+z- zuWJJwTMhThzN3EnowN;=$ZT=r^f*?%jGiNY=jnPLb*Wm2ZFdY?+^Fhx`vCyVH4rsX zXGC9S!pJ$?z`b}UG;%yJ!s4nLg|a->D1Fe9cOKK23k9XVs2SgEHaTGJdl9vHpMRvY zO+0IHu~7hf??k5+&$;8`xhMuQMZk>lqRCS zsD>v4wkS`#Ram1f-1&1>YcMs43BMsuV5h~O*@y_-@GS2@2FEtG|wuj5-(}zv1MVe0%Y@DHr_eCMaf}AwA z!I_1wjD-2!jv4~Yp)ucs$1rct*&n|_bm8bV#4$@KBp*j4B7OP#4gBW9^)u_DZI|mu zBM}-f5ZaK*3nUONbO}Fj;t~KfFQExa7z49?q1>kwf!11aafp(Z8>k!U&v=d zeb0umm_ebyAd?B21QXdDRxw#7xE1$26%rfgXb&!{%PZO}W0+@)4J*smQiRb-k`Y_4 zEh~yPi^7s*6j^EsrD%pY+3DU3f#y2HvJd6joQJ%G?oI@@EhCZPzJSHAgQwMRMHs10 z4nND4N2XU}$!py%$Yly%gq#^?bA)?&=bZyP8qH91*8p_KWG~PV-eX&d1U#R_f*w0ucZ?&6E&=G%!wpB)~VDUE1z~3``%E;5hvLNON5Gf-CB_t`aP_w zo7&Al)~o*cxw@)Gs7gfVW=O>nl?9^-re>-?{%aMzG5*8S!IHQx%o3YmC|++YS>|vc z64yBJ)>N#0eJND^&4YtIZKp4)kDqWR3;)_U>wC)|OlZ*3*+=Iz{pd?TwXPCZ>12*% zatN1Qy&10F@vC7-Y?S#gez*>YM1DgL#NVXh^xb&WH!c)4m<~&FUPe%x?wWmoW zJVf}dCfly7|91|IWSI-gEZaXL*>D#<0xS_Em@h5PEEZxc-Fscks-eYKTy>!TP}qkmGn#4O@v=5N0dl{TpN4+!&D zYT4JAIrE{HFnR@NJXqW62yQVzxCv19Cx3h*KFv^WM`e!AJkdwNOpcsKM~wdeH>onU=Ds37xfN;A72uYD27NYCw; z>~F1x$48Pk<(_(8ix$2pJ{5YG)pG=%%1_o39&U-4vY8HG%OlCEjBYydMk}Ow?V_2^ z2FxF=hMUZmW#Q)T;1z&d3 zuDkNt{ca+*z+{&V%k#+~jQ2rRx;R#kVR_j8Qk7JqZ6+HPI29rj>7H(E^OG*#4Lnm* zBVUrl`50xQ@f4|ogS$zkLYAo$?wTB@zh0&NbS;>Aa)w&Xiwpxm%W4G4>|z%0Zh1&k ztCsDx&Ey{(=V{t?>tfsClZ~30&2hKeyMZSSZrRps@~)fwvCon^rc=#p6M0fresqGZ2RZ6rGK;6>7(M}8|utzz*m7>RC zPm7xZ9cGZ@lnLI#nomr=K_t9U^mbi@&Q#D7%_!SbV?4+aXRV%{ESqFcqVU?)`v;(rcUX#o}r}Y3aaoVql2kUw%UJf zS{&-wUeHh$#e78EO(TtNhPts4Uv<57qg|JnQ_W)6NP@J-_y8kCNPPSb0zh;qM*_fy zp!#74!`@=22r3@-J>LvtI?FbKYB=uPzg>gql0I4S0R0C3E5ZG53&Q+&xD|6fT(4Zl zWdGhW!Zpp@U4jDv{Vo3!%gE32FUv?TOfO6;B*Y>_|8Fc~(^pe8|5(Oc4UL*F<^LWU zANUr_1p5WT2G9Kumg)3M3k4Olp)S7nM4M>i^VyRn^&LDqx6w~|> zUGiw?$4}P_p*ab!O`7*;BVby?q>^Mmz_Kt2a1Gip zY?fZSfSnZ$(ejvan-QOW`JQ#irY{f+)F&$1*QO2B*G{Fn9#LQ2jBci9$1vNwW1Jr} zFd+&Ro*s*W!t#rX(pp&k|M3MS)EB*=lbfajhdVT;VcA2{E^DGF*-@<*HZcR3uUGf$ zm##`!zKuO8utk_TfKSi9-KAa#x10@Ne|MO|6P;G&!|>@oGt;bhTJjh01-BG;G*OGI zGn%I5_e>}i%*Z_Fx^?PdOo#^KSkjZ?_V>=1Mb2fL;uIg5B^9mpPvdViSNd{%(QOkP zAq;zN>aY&yHtK8Ts`9k>?tXVM{ZE-(iUk#2_=`B%`lR zP>b59mqxoNGC+?j(8*nmK|OL29F4;XRfFeLz|mzlUCkg<5&5xC1l{pM*0yT8@r|2p zuODOzG8y@+Yu_80L8edwp?pFFimda7P8~_}V_UI$GQUSJG@7UYMQ$99oi8lP9uN9p z56xVXT$hrCDtb<5#b0PWU1)ILx=zp1g-?dn6m0Nbm4+_5r|6f{FWGBvRaWlKCXwF7 zY9D6dx{LFX8tQ65hWw-uP5nrN?-d8?TjBI7-Y_9z6d~}P*2Ez%S#uV$1Dr<`WD-Dl zafh8%gY7D}$Yg1kE7w#&_&f3xBqzrf)zD#BFwIHlg5^LT%VsCJz{{91b>QqeoX43_ixGp1T?+9aXz3Xut>^qop#tbO70aAB|)1WjC2G0-a?kD*22eX!! z5-_xyE4P-9B%bj4C2u#t8H>(UH1j_sx=4+SNVZOK>t8B`S1P9XZ0woh!VB{VGZuY` z@)r!#JCpcwnsD?uEEPn_WCjeAC}tTGfLk(SodfmZJNV!FzPaPulM=^GM{xGWvQ1YB zwFy19VPbT|w2H$YJ6NKH9oejQ1;B@~;hP1IkU4QQMe_L^#8RXwmoB793RHy5EU@@i ze&61SPrulqwtJmH^a(9I_ENn9vxOzGE%fN%nH4!YYwSv>ddGXvMCH#v?X_t>3DJlqXM_44qaIC0`@Q-N?yGf|2YG&_o>my@vvRU+56 zc1qEu4X`kKF}D7R_L{6YH97%sM-ZnLtF&y(w=Q6IGx*&vDP7s}^0Q>`(;?*tp{dqB zfRAZ{r5a`x+ti-IyczW?*T&XlOR9GOlg{CUaF90aiTFo*qk{nJBcXou=;XUk_aRgc zk$p{6@@%2oBhWJ!TN8I^NAR%K`lM7P(pVhpxK&bmVP7SIdB+;-zz?I~@?OX9GGb`r z`ISy8J4KG9#YLqN~&R zTVbAP^EloP&+tGn&}fCbJhfFPRcW}f)Mz&+`($2Fnu~wQVbo&{Fg;-+h;sn@9WN?! zmw4RC<8Mj~_6xUhgIng7$Y7Y9?5H3aKfXXI28yGF4Pk#S^H4=*_vjAr^fYheE_|vJ zH{3$=F2MGP!LhTJBhHsv7$=UOJH2>$OVgIkE+&*aWT4|s*P_Vk%(*ENM2sBw82!iW z4ishZZ0GvH5mP?Fbnt0R1)N9R$R5k5E2dllpoM!6yuhNxZA^Bgu;m(FdfAK zUKDnY|BYdvJfB-J8*rvGcFkBn3{TBLy6wSQD@B;W>2Qk`#!SJ_oS+*Ux%2S3IFEN{ zcw^JB{YhcTKB`vhhDx#}n*s~g0o8&46|6_}Ec;5h`QWp+dGa^TNxD1-q@$+n``TS0 zifV;&J}lVPTRGXXNm6V%^=DUdiQatAbux?qb0ji~!$L;F#OhVf0)P1`IOYYUP@n~* zMRp+#7z-=GyrYIr{*bHy^jz$U9X79fzuiTz>DSHVxwu|L&f5k(R5s(?htc1(`ik8H zr9#)MLvBRQaj!HS{CBg&uKRY@;cdVKam~WOLRP|o!6ao+nV27 z#whb{@MN5{!hvO~Q2N;+%U216D`rtDu@QG%Wh++o`3R7QqLhYS$STz+Dpe~()g{a? zID%KWT|ReeKQ0alq$M_qCW1%z;gSpOubZkcsu*%p4BBCJSW$%pCCNl~%u$|7D*V z9P>YX>I^PPED@w3Kmi?gCef?^+}<>DOBm~j_Go@j*bm5z@?mMwhV=YuM{ucXEj=Q+ zKxZS=tv`@q1;gwH185ufvG&Yp7}-$u8t4v!vZ;*33wsljXG1*~Uf-^l-FeKsZl8^v zZ2)hF6F*4MfI<042Q+Tt@gRcmh6o|P=%e!mv(rNKD z??!FOb%)u)+``;Gv(F?6bC~r;*5MVJy3v_*Rg5_XYHB}RM(j|k_;<=|x>Yqmc4yHD zjh74~#|<)lo}DtNipRq`Lq{}ZSKv2 z>>3H|4ghfF=`gYeC;~on9S@f!mmHOo*pwGjjaTU%AS~m}T5ax!tED23Md-Q&SHI6LMg8c2=;Jt0FyL%Dj7%A_bT zr92QfiWV`p(B5?gcL4cbYm=i6qk~;AQSSFhFs6l}$PD#c@5v!DTf*Yu!f4wJX2F3G z3Ntz&O1nja#qUHV8F_fq00dd?p~a*JOa_4D((Iw|uu_z=j$?Bv3A%e8X!)X8s3(p4 zn=jRgEfMrw5@8Gs&kGDMo|B3KEaz$0Ep_m)x)nMV7R(Sv_p0qw7VB#Dx7lVDnU{@# zl@MuKL-mhTZkEuzW{8I9-@3Gn>s!-K#V|sV(N1FZ3dsmK9zGdJ(5DWx$bZr{zmnHW z$+7Dxni2To7Y3lqO7qJDs=}DbsREJdrRi$g<*qG_Pl!J-yU&56Op`;WbQb>5*yfySq)RrHr4#Yx(uhG^sb6_$9&BWBTkXFQPG4h@e262dnG`N? zni~%P9?2CdyLoPx*%4zFjmqM?!qV?bqvH4=SlHJL5b1lbj~+pmDD-NU&xQQ9IG`4J zhWcGaRFR?Sy;PQ0gFO2YT_QhiOp@ZED;d9^1MtpZkt~4wVXFS~(=6coNuwC;Ux7@p^y|>2D-X7!xy$!TgDj-V92i3?fpa z${!lkWWy?D-BOJ#$*hj7&q4ErhLF!DIN#91 z!+!0)FyTixPO4!Smk;T%yrVggKXa9~P}&5iJklpt+0zA>V_q)l9c|LtVX`)Q|14c_ z6P3Zf#Frt@{HB?^4vwJNE7uCvv}N$!*P^jLcyjWSmbP1i*jsyc=*S6z(0HL*<-q6K{kg7SvQ|=jn;QY}3`MvW}vn)aoc1 z(dDYCws(qC8j5NYHrnS$k!T?@=xUu3I+{i%<$^TU5R?U`f`koTUJ|2U$Q__*MIPeg z*5PMIOk-+5J#{JFUDU_+PFiNMG)sRX4p(u^=Vpzr z%z+Ckr1uMHw-Xqy+aYXYZS9Yi$3B`@6tsAi9(BaYo$?KTV8U%J7F646on&ZezKa=X z)lQo*M7=)?dNyr_v-C3|tUPSm`1U=>T?UdrciGNP&igQLjef8Gy7?g5VX*O`-jT;? z8hM%a?kxAPddSSbS)R0rc1lBCx^AAQf~wU0#HCA4sgaDJb6c%ytg$g|Z#*DaA&sn) z;l?%M;fnh{{J`2=vn>$;Z}BGuXJ)xBQI-bBL?5$i@)FVznpzjnq$PsPz%OaFzQ;59!+kUzZ43v4@vG1hyh0r$?ebBp5!D*b zU$>}Lv~vxS*Cc~c+Nn6)Tn{h5Uz(tz+y3B&x@JdlbnZ=mQoOeI$e7~72%OlH$f+}6 z(IU*zj)!3nc-c@(Wr2V01G$7bGey7l?*?JrIss)~AJgcUO>E9=OLjtZh@ko0WCIoI zbyk4XvEY0luDKKUY3YUOm{}PG`Dp)5kQ@Z>tEGR10x%~l|0@5>1|1gl zKMeZD*cXHj8~iH!MWz0^z02Zs2=64&9TSntejen_75NqXm9Jk z0qDl{fPuey4+PZG0}A?&U?1?~pEsic?SUb}{c~pcCo$eXLJX!P?>_<_ON#G50FANJqz4;7((!X|@t9UL{=+3i%9RXX!vua>P;MR_g3xpyth z??K`#4+HnCU4=lWX(l<@?mn_ZIs629M8OdN*rDZ+DPX^Uv_3Y3Hz5|rLM(BHWB;mM zJ6$X`*)Ce61^Z=)0o6ZIe2E-&Oj!X}ZK77G-08jtqLryk)!6_$-MYdwaVWOyG7kD= zwbFz|-0YVSgawTQA?M)ruqTYG>(x9YEX7e){-+4!l7Z&V*JQNxTej z{AcI6U3QG2Cz5bhn%ZJ_DGDjgUEC(&2(wAGQ7YB%tE;JbOsU_;%5AN}oJ+rBAB^L? zns}Kr4>KIaF;Lu9APtlE>>-@n0H*ccZm1AJm2rW~HYUj-h89Xs(f=e@mZwNkpU*wa z=5sey3K;s2Fz{oWlpv(dfE#BMl`4{3YwzCb>rWPuNz-I!M6+j8@SL`WmRY2CL1UQ+ z?Ib=jl%C>Q|0pN!?EPwZJI)~s+^rJkBA=dSOtO$}3_ zzV%>WbP6(kxgo;t<}Z6jR-0MkdpNNLlvZjhb$CUKzg3kRF711AR|cb6!?KiI_pub8 zNKnV%WGk#J-%WCOAPh_3anHGNTW6_c6?G8VgC=Doc3RwoZX<-zi@IS^&6^k$0xOeI$faIJadQG z_WC#$ffLeF3WugxRN_A#DPUR<@pk>pJ;s(q?o6xbq{bGE(yY(WSDmVD#(T8`OgBeV z^}<-`ykfLb?82O_QoXsmcoR8bi@gXg@76iAqycA<4x0~=X1#jml=@hR=%7OwJq%KI z#MpnJe_2Q9FF}1$p3CfuToj6hZ7xgR5In0m9bp2k-h%gikM6m31O z+8&T?&$3fjlyOgk^O{dmupDX0U!g&+!MnnHHW+%t8b6f&-)oXNbkKpt$T@>$v- zH~%gM-@O?XuojpTYd%@SjNhk+Xyi0$Uf}svtI$g_qcK~z;DF?ut6M3ucj^ea%&c* z&|9cdmH}e)Z~#0MGk*5Q=wyB5O0pD^_OXy=+Ol*Hba4A%W+orB!K$8AK$l z$&)y-_Q%5cNM>I$UVk9aW2wrV{-u_~oO#Ip=Vg%iyyH&$>Yc)7=4L&DJLU#~38tOn z+n=Lz>)D-S%z2n(p3<{&muiV{_wQb{*NR;nzzUh6cFA6{?g4^}PQp^MH=oiHvX zc2?3wdXN%DE>{tS0MCiYKeQ~UUf>kH%T)lp!c&%`TX0n2Gu1wqM^7vBU`G~O|08dq z?anF-IflHNHLr$FAv`aeBp23Bj>=h?O3tD#uDM`p9EXYI2x98uOFZ0m~OZQv1iYB^FZHlLirdlk$<0o^52VCZ#PQm3}o_rf8 z6!UJZSrtSTLsO>PPBvEwEuWl!2I+JfGY0i*nT#_Jir?2h=!KIq!2#i)d(77&N=u8G z7VKNEzZ#{+$7k;5w5(k?Lp_I`_Hbp>dv5|y!TT^67fD$*F5Pyw#2QBlSG5r~s-7mS zgI*C=yc?z*@H>v24ALK@G!im8=}@`Y^GXb%^g|;_CUJmkZ_8dnCT*H5e6K1_(EM(0br#$gf@YVwis)L^CTh*) zD56X7JERpjBT9PTOTW;uBX7_7z)mf9#O<1O0r#bznC`t++0?#gXtA)1Ca>+~a!3SE z3%2&y=3Vu8A($9*U2x3WeZidn*f3Jp_#u;%HS<#0BnWtU2}IErXAR-vRYkeR}>p^8vU8gI{NJ7U|G@_Hrvj*0)dR-iLiP`Zh@)^pl2j@?>Et-Y1&~{Z9n4 zOxUS*xFr{4V}V~`(H$(`30tzI4e{MJ?CA8mSByK2+Lh|LTwU}=@+$1{8Qm_$U{}FI ziQ6Grt;;MMNp*DBU)bAwvd||3!h^?V*-;j1Y;sDy`9l`Z&BOW#17hbL!oHBl=2N%( z{e4rpO!f&&AYJx2QqkG&+-0)GjmKo?;!|s5U)a}6T-)>32Gy5pn`q%sB&SrDD5+`e z4w?4ZkY2rLvbwpqmtPp0ekAKv8S<>mb@f!aP_=fL&QN`7J2rrCcmv$*p575Jy;dBk zJ*LmQfQfwEf&uZj3l2o=X|!&W{n=SQfS2P+)WK&+P6{}WFSr}0N6x?CZcCd6msyA0 zB0GtFUUtnqQe?p%S@BsNpWL2VO_u;gXCF@{w+CMzXCIY^D~Wbzbxm05)cWD}kY#oW zjfZdd`mMs0)Y*mZa?)%Y&4(m;y?^I$gywH#=nN zk31}ok!EXg8mNAE{Fhi}yVjfchuv&it47u5Z1c|n+_<|* z=D@&*qTGZtR1kwF8J~vOGDv&)fN;K_JNCC;Um&-j(qxH2*w{0ddDv@#B*=Qr)9F8g9={oE&A!lW z?S-(D$sLKuPr2{Y)osY65`e?nbj=+1=f>f)m&~kb79OwkO*c7Qko-g!jZp$FPaJzW znvIlm)bp5EOMrxZ}nQnAU&u*{Z+)WdZw2n)?6S)%zcP zM*ce=kSZzf9cr(fzdii#qx1hRi_gKx(b3G>#NqF&y&Kdu99G%kym`6^c3pajlCx-k zVB-}O;QM`>9Y0R5MlBa!bSGr%?z$ZPoq;4NPV26(FV;4z-D#sTdVeTHD6P$F7IiaN zmZjW|7{d*wIceQKWLI=o_1JPf#Ux#{9_;Sxjo`;f^mA|;$%}uipwgs|MLW+BJN2NI zS`D<-`i*@MZ)xnr#$-vsXeBvl>*je7Dl+tR|HhM>Co?-UFD8+p2rRGW>! z0;gt?RnEQEx9*x>`_ZfSVQxZWvypA#J^fY)%sjZP5uIWr`AZX{%Fa!#rM;cnMq)+B z9=4EJ#<3t}nFJ?=R>r#Gp~PKI@_}Wmj@D&vVN~e+gm(K6+@SyjDS0k7JsU_zuC70+ zuUM6yB5?5W(P&a{%Wn^8-Q+tmM0cC(f{+0sY7kZ4YOAt0Ac-Ye`jUNbluIy7jRj%3 zJNKWMV-0;=EfiOi11A%$5j1?fA;Shwb;j5if}c8qYAadz3yv^9J8X7++&ZjYHCSdP~m*$yWEN7%Y1kmjUp^ zqkynZ=;KijQNa>7Aalurfp~p8od=RGu;zFHNI^jc2r$VSx<86o1LI8`oa_oekG6~< z8qfTs-gpM_>7P;lfQ|oH;5I)B-@*?i&e^Pyo%scgbdpkQ%6icvAIrY#7sMQw6Dikk z7!%MVWO{*uJMAe`zddIZEl%;?FXcLA*ee)L-eQ9KjQ=DVHzN#YFv@G)(CljHz4QO^g zNGETZ5?fC;H~=Cov}cG_*O+7gr!prSZLR7KqG-TJIn^1)wJB^uA;~FTj@cO8{~0b1 zkKM@@l0Wxw9G4Awt+klE7lIOOK@M%7zprLpw+&uIE?q%~ablRZVMQ8?PemM7AP2OG zJbjQ>161Cuo5H0?VM6OCLR|=)xHTk3bE93)w4b-Se^4xErK{_Z%rj)kBdQ=1{CgHTy zoHeZi`GeiEI=r3D0Tt6Px_(b0Mce(P$J$m4N4)M}VoC5ra09(RI4f8!gj5V9N6LQk zvu=sRRRr@MZqd*VLc?mshAb>3eEUw>1NJ<0BbNSy2mY+1vC!1t*L}GY;YAjlzvEGS zmTQ_FAXMmdk4?HVpE1Hm;1$o>5L(fw9*D^hG@|U{9O0~a)m%aq%aA?3n85vw8B`{$ zurx}wa3Thi;b9q68+|nKy>nH4JCm1mnKgox`Ma#rVXvTB>Z);#7}7FWG0$_s>#T5K z8+3iQem1w&OpG@DrEAcSXG%)4X;K8t4{$(|kqek3y}ti_L#P1EMYRxqgqu_XvoIYt zpmP%E{oU6zs1zO;o%lmO4hyH_aXgTU9K!Oe8m*4xz@Q5O23QTq=dlJmIY47cz5J2C zhZW!ZFORUxu|{66a+mPCjokM8a-Ge48iYu|-vsJZ^ss)uuiRfl{QsJY{GScIkY59| zgQJ_J(LV$4hPp)b8Y@EQWfd*sa>q>LI?Y=8q%KSM1*m9kxAQ@D(Ko6Y6cz-sm;~JC zdj&$F&?Hig_={tKL%4difzlln*d%fH$J?4=5)T5x{WH3-qFYmb)n0{B=jfR#ozI}8 znW@Xqn<$$mM*PzR5+%MAe)&v$0+Q;~kp?1e;Y3}FD56A*-%tcgJwRU;5?wMlM}nYYJh z1x%WOlI|qL7k%`$qe`HGa z7`y5FSmfaR`SeXHQmEOsRTgC#Qks5q6wc5>xh)Yl4I`0B8DYgcvT5GCxx|Ur3L!S3 zXQEk!7X}R)jsqv(XX?OZjprPq&zbwBrLg0Wphy(6rQuF^%yh0p*1x(3#U}YN1~m=_ zySa^N=PEaLy3#P@pH|$WzsloFwI|>70TL6Tbl&n@z`sq1OqOLZXOad%{j4nY5$uES zI9&+?C|iCI3@;)_;{3VYvT7obn5*5ym0d?qq@lU*L~=y9M0^fP&5$M-)$|c5{%v2J z6jHBq{}iO0K$~149ZlrLg>fcwR^6C&9~?A{NbcwfZKBAoJ%S8sR>rHHWhjBX&}_xeyP{mCT9sXZl99MVm)a3E?-i6z590tg8%xUnPRyAJO|G)DrGER5578 zjTY_4osl8Q{y#l%7ZvoAIIg) zsiLm7C3Lbb#2xIhVwPnYRuflZxV=NwS*PT!C2^RaL{LF~;EhQe38O8xgxF^k`X<&4 z5E@HEt)}qMZ;pl$mDU0~>GzRsulv5=`#Sms%0s4()W<#FIX5(0%O*m0daKw{)~9K?+b6vn~7xOgOo&{ozkVgLg6Z`jZ+KW zM<3B!Gp};r?}x>Ft?%0AKlG1cC|-qQWTP&K+BqZ__Qz!()hmck1VE6*?r`MMzq3}< zU8L#j=xwm_!W5|H&*<9OP6jZm`n$#OSTW!4zw_Ik>|f`ws+tlDky=8|m7Fkm1_c37 zZUM}kTtVZl%7c)UIfFok1ugoQmr@g^KQJp3yazL64#zM>7)aCGl2hAI55Ya-mLS7a zs7|a~6nthW9{)5AE@sQAN^owz_IxNx5PL?b^N|eafLh1NRtl6Ffp!uZa94xTiXH!J#YtN zZOe)~+3A#7I2aH+gYOa}LZfvqOh8ya} z8$XW6cF5;&PNsf8VK%mPa9F}_+7so(&oh;DUf+d@Z5fBBrVJPMj?1B4x3VEt3k>#O z<-n#vUW&Ef$lRpoz9oT3-4`#fpX)`frZrk&p8-Wn`8ule0{Xo_QI?mc$0uhxpG^`E z7a5%KNc$#hEaPFONH6cG0d+HmPmLY@vsibYVQd%8pN$TYn?Hodc_hJl`lJT8{azL0 zZZ$VA7l&S==6tf(0m5ls88=!d2av^kFVy=+(Rhxpt7RzXXT2Aa5Db4_aT@A6z+>2c zRw-iM9qt-PgtAAlt;Dw*Hz5nr@E%*f^p*0ySb_hpEdQnesJvgK&f*T0Fvr2jc}fla zZU+L>{*8Wq6MK%~GiDh^f@+P@di#eju4ouDiN}<{DURD{x`|4W4#1b?e!)~fHBD^P zAaM2mWpsQ*ne72(d&|y`J#bGn0@Vh3ckNq*O&=Pd6Ks&>OKbZUaoLLo=l~mR`qEy% zw6D*)zy@8uwBTmR?O=nCU)ny<;27=T*i!e?cBEcAMz<^SpzA#b8Vvwx&<<{! zHPGe_AfGlT;+{iXH0N%ZsOyfgMr&E1TM>g9 zL~)jc6`RV7%kU37FXh)>@910cF3fV&4dG+#&35#=$7Q=jZ>Qq@7TB&kw;>HtRdz$X zpO{De7J}+f{N`Z6Ru2l`x5@@immNQT_9#f0=}lKwm?aSPdY+f8v0wgy{Z;Y4C=mUJ zmsl$1S2No-%zC8E*5)mZ$tXb-uw-UWTJAhzmC^0Gt}+9^ODeY@r)#r1yKfO3DiVyJ z1&c#2Xd(HDOd)O(Y^F%JGyO&p6O~RhLAevv$b>$%C#T*nJo3|WhIF*u>ZPYSn3y=p zBtJv;&r4>>GuUGhTP@ojx<@_m0{ERg>d!Rfu*d@3GH!rvT1l8 zD4*Mp50}3)7{yN}!mzJ(Oa_|&*$n1y>XwzBwVAQef2r(BfSS0%aI8=-Y#oL1LWvOz zqRHkG$To?1KvhJ9B4|Z$-7LxCCL1>!Ba9u#BAyjF3ay}3QE9anJBUmX5Ra-Y74X7Q z@nEQEYe!Jj+Dq))B%5OmZCxhJ?!W*4{r~^o|K7fR`}SWGEuu7OjRlQ{Eb)+aUCL~% z=~@Kj?M($YRHyGcF=hQiZ>YO?=SEfb)>Y_ebbqob!T;< zF0&KOG+#dR_|EuGmhO;t#y+TdH{<2~9#Qklk?n^oSI#6Nn)Yh{%)MXP9kAfN!%Xp2 zKG$9H1`l?#z*}zaxoC!c*V1qaP?;a|oLG<12y@@9oC^N&S7MY2Ck-lrL?jmQF#}3! zz>T>|upl8y7%rHq9;hVK(r^@mH6&`*gB;{SMxGBu4JO!jN+mE;2AD)lxCu5OddvjV zC`=kL11kc%a>G_dHp(gjH!N2PbTn;*A;@B}h%7P@NogU8LZN`HX9adu8q~pOG*g6? zOM^lffiXsb#5y7g#PTv0{$HaQURRSyl5{9ye6YD_RR@+D$RXP?t4T{~G=ziS#R0%8 zgS3zap%LLq9J7pPC1`9F{jWMCGKUU($-7jMRG?<-gE3sKw3?4n7(#Kkr3Qsr8HrFV0b&UfDJ%^GVj`Jb39;vGdN2*n%-RSw zX3DBhJzqLAK@vVo9u^~g->%>l9(PeR0|j><>QD~1oowUPVg?K-ASrb$sDM~&_(5_J zh?~G9+#r+kon)q7QjHXuj-fOpmx%R}@WAP2oX`jrVWGf&tItk68$KJBLK6+#Fwr>5 zxAM`*G6EB#q}f2L1fVfkiMSroI*3#3L~piAAjh;(eu&a0=cXQ?B6qD!_9`D`_P_u=3LL`$L&?x?tazO$#N z=KQIrzf}+2J2<#;`S#KiK{~Je7Vl5L@>Qwt-uAlHBr5YOto738_lT*C`1+cO6?5L1 z(vlpMpSXM2>HK4T7F{`?$dBoksITYWu2c0HSG?rom9_bU9wi@7w_Nn|-H}DEhBhQe3~Sb5r!e8>hXdwcZ%DEv{<)%P|*J+Or`S!ug#8ez=+&oOv`bSrca* z)(@2~P0zXz*qo}L**?kgn*4Ug7J~k~KUmK^Kf2EwzC4f~4RqhSg30kIXQe(tphlS=)1$j@dK?5p zh7sdRxpLVuZ?TjZurq@+q~Th7!!}8wG=c=32?enzuG0y&^+z`SEC#spctAl=6!g&6 z#tflmin4#hf(2zAa)R)90j>u;X5}^4G;5PILDO+sj~Go33q66k`#BtxCl?G{J>WBE6D~3H^m<-$K&CVpvk^Y!apuFH$Q+A zdc%U=pnJ&{z=h_%VCjV3liVw`=hrQ{(A+mLoY1Wx|Dfjr5qo|ggA2`F3+jYEMDzyT z%gRs|nvERSiBtCg$XE>~OI@B*aV1@ESeS`b=k|21>ohA@&UK{juCZ#f`^^n2$%Y(v uB=6MtY>RVT&q}c#x?V|`ae#AsxUH8_!Te}%keY(W8xHXPlane system. + * + * This sketch was developed and tested on an Arduino Mega. + * + To report problems, download updates and examples, suggest enhancements or get technical support: + + discord: https://discord.gg/RacvaRFsMW + patreon: www.patreon.com/curiosityworkshop + YouTube: https://youtube.com/channel/UCISdHdJIundC-OSVAEPzQIQ + * + * + */ + +#include +#include + +#include // include file for the X-plane direct interface +XPLPro XP(&Serial); // create an instance of it + +LiquidCrystal_I2C lcd(0x27,16,2); + + +long int startTime; + + +int drefTailNum; // this holds the handle to the dataref + +void setup() +{ + lcd.init(); + lcd.backlight(); + lcd.setCursor(0,0); + lcd.print("XPLPro String"); + + + Serial.begin(XPL_BAUDRATE); // start serial interface. Baudrate is specified in the header, dont change + + /* + needed for initialization. Parameters are: + a texual identifier of your device + your function that will be called when xplane and the plugin are ready for dataref and command registrations + your function that will be called when xplane either shuts down or unloads an aircraft model + your function that will be called when we have requested sends of datarefs that have changed + */ + XP.begin("XPLPro Multi Demo!", &xplRegister, &xplShutdown, &xplInboundHandler); + digitalWrite(LED_BUILTIN, LOW); + + +} + + +void loop() +{ + + + + XP.xloop(); // needs to run every cycle. + +/************************************************************************************************************************************ + * everything after the next line will only occur every 100ms. You can also utilize other time values. + * This helps maintain serial data flow and also helps with switch debounce. + * do NOT add delays anywhere in the loop cycle, it will interfere with the reception of serial data from xplane and the plugin. + ************************************************************************************************************************************ +*/ + + if (millis() - startTime > 100) startTime = millis(); else return; + + + + + + +} + +/* + * This function is the callback function we specified that will be called any time our requested data is sent to us. + * handle is the handle to the dataref. The following values are transfered to the callback through inStruct: + * + * int inData->handle The handle of the incoming dataref + * int inData->element If the dataref is an array style dataref, this is the element of the array + * long inData->inLong long value for datarefs that are long values + * float inData->inFloat float value for datarefs that are float values + */ +void xplInboundHandler(inStruct *inData) +{ + + if (inData->handle == drefTailNum) + { lcd.setCursor(0,1); + lcd.print(inData->inStr); + + } + + + +} + +void xplRegister() // this is the function we set as a callback for when the plugin is ready to receive dataref and command bindings requests +{ + + + +/* + * This example registers a dataref for the beacon light. + * In the loop section of the code we will turn on/off the LED on the arduino board to represent the status of the beacon light within xplane. + * On non-AVR boards remove the F() macro. + * + */ + drefTailNum = XP.registerDataRef(F("sim/aircraft/view/acf_tailnum") ); + XP.requestUpdates(drefTailNum, 100, 0); // Tell xplane to send us updates when the status of the tail number changes. + // 100 means don't update more often than every 100ms and 0 is a resolution divider which is explained in another dataref, use 0 if no divider required + + + +} + +void xplShutdown() +{ + // if you need to do things when xplane shuts down or unloads an aircraft, do it here. + +} From 8d9b93be73136e7cc42d26d7c79bbc26f185886e Mon Sep 17 00:00:00 2001 From: GioCC Date: Thu, 14 Mar 2024 15:12:55 +0100 Subject: [PATCH 07/13] git housekeeping files improved --- .../.gitattributes => .gitattributes | 0 .gitignore | 367 +++++++++++++++++- XPLPro_Plugin_Source/.gitignore | 363 ----------------- XPLPro_Plugin_Source/libconfig.lib | Bin 0 -> 17048 bytes 4 files changed, 364 insertions(+), 366 deletions(-) rename XPLPro_Plugin_Source/.gitattributes => .gitattributes (100%) delete mode 100644 XPLPro_Plugin_Source/.gitignore create mode 100644 XPLPro_Plugin_Source/libconfig.lib diff --git a/XPLPro_Plugin_Source/.gitattributes b/.gitattributes similarity index 100% rename from XPLPro_Plugin_Source/.gitattributes rename to .gitattributes diff --git a/.gitignore b/.gitignore index 259148f..c390194 100644 --- a/.gitignore +++ b/.gitignore @@ -24,9 +24,370 @@ *.lai *.la *.a -*.lib # Executables -*.exe *.out -*.app + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Oo]ut/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd \ No newline at end of file diff --git a/XPLPro_Plugin_Source/.gitignore b/XPLPro_Plugin_Source/.gitignore deleted file mode 100644 index 9491a2f..0000000 --- a/XPLPro_Plugin_Source/.gitignore +++ /dev/null @@ -1,363 +0,0 @@ -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -## -## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore - -# User-specific files -*.rsuser -*.suo -*.user -*.userosscache -*.sln.docstates - -# User-specific files (MonoDevelop/Xamarin Studio) -*.userprefs - -# Mono auto generated files -mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -[Ww][Ii][Nn]32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -[Bb]in/ -[Oo]bj/ -[Oo]ut/ -[Ll]og/ -[Ll]ogs/ - -# Visual Studio 2015/2017 cache/options directory -.vs/ -# Uncomment if you have tasks that create the project's static files in wwwroot -#wwwroot/ - -# Visual Studio 2017 auto generated files -Generated\ Files/ - -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* - -# NUnit -*.VisualState.xml -TestResult.xml -nunit-*.xml - -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c - -# Benchmark Results -BenchmarkDotNet.Artifacts/ - -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - -# ASP.NET Scaffolding -ScaffoldingReadMe.txt - -# StyleCop -StyleCopReport.xml - -# Files built by Visual Studio -*_i.c -*_p.c -*_h.h -*.ilk -*.meta -*.obj -*.iobj -*.pch -*.pdb -*.ipdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*_wpftmp.csproj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc - -# Chutzpah Test files -_Chutzpah* - -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opendb -*.opensdf -*.sdf -*.cachefile -*.VC.db -*.VC.VC.opendb - -# Visual Studio profiler -*.psess -*.vsp -*.vspx -*.sap - -# Visual Studio Trace Files -*.e2e - -# TFS 2012 Local Workspace -$tf/ - -# Guidance Automation Toolkit -*.gpState - -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user - -# TeamCity is a build add-in -_TeamCity* - -# DotCover is a Code Coverage Tool -*.dotCover - -# AxoCover is a Code Coverage Tool -.axoCover/* -!.axoCover/settings.json - -# Coverlet is a free, cross platform Code Coverage Tool -coverage*.json -coverage*.xml -coverage*.info - -# Visual Studio code coverage results -*.coverage -*.coveragexml - -# NCrunch -_NCrunch_* -.*crunch*.local.xml -nCrunchTemp_* - -# MightyMoose -*.mm.* -AutoTest.Net/ - -# Web workbench (sass) -.sass-cache/ - -# Installshield output folder -[Ee]xpress/ - -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html - -# Click-Once directory -publish/ - -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# Note: Comment the next line if you want to checkin your web deploy settings, -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj - -# Microsoft Azure Web App publish settings. Comment the next line if you want to -# checkin your Azure Web App publish settings, but sensitive information contained -# in these scripts will be unencrypted -PublishScripts/ - -# NuGet Packages -*.nupkg -# NuGet Symbol Packages -*.snupkg -# The packages folder can be ignored because of Package Restore -**/[Pp]ackages/* -# except build/, which is used as an MSBuild target. -!**/[Pp]ackages/build/ -# Uncomment if necessary however generally it will be regenerated when needed -#!**/[Pp]ackages/repositories.config -# NuGet v3's project.json files produces more ignorable files -*.nuget.props -*.nuget.targets - -# Microsoft Azure Build Output -csx/ -*.build.csdef - -# Microsoft Azure Emulator -ecf/ -rcf/ - -# Windows Store app package directories and files -AppPackages/ -BundleArtifacts/ -Package.StoreAssociation.xml -_pkginfo.txt -*.appx -*.appxbundle -*.appxupload - -# Visual Studio cache files -# files ending in .cache can be ignored -*.[Cc]ache -# but keep track of directories ending in .cache -!?*.[Cc]ache/ - -# Others -ClientBin/ -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.jfm -*.pfx -*.publishsettings -orleans.codegen.cs - -# Including strong name files can present a security risk -# (https://github.com/github/gitignore/pull/2483#issue-259490424) -#*.snk - -# Since there are multiple workflows, uncomment next line to ignore bower_components -# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) -#bower_components/ - -# RIA/Silverlight projects -Generated_Code/ - -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -ServiceFabricBackup/ -*.rptproj.bak - -# SQL Server files -*.mdf -*.ldf -*.ndf - -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -*.rptproj.rsuser -*- [Bb]ackup.rdl -*- [Bb]ackup ([0-9]).rdl -*- [Bb]ackup ([0-9][0-9]).rdl - -# Microsoft Fakes -FakesAssemblies/ - -# GhostDoc plugin setting file -*.GhostDoc.xml - -# Node.js Tools for Visual Studio -.ntvs_analysis.dat -node_modules/ - -# Visual Studio 6 build log -*.plg - -# Visual Studio 6 workspace options file -*.opt - -# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) -*.vbw - -# Visual Studio LightSwitch build output -**/*.HTMLClient/GeneratedArtifacts -**/*.DesktopClient/GeneratedArtifacts -**/*.DesktopClient/ModelManifest.xml -**/*.Server/GeneratedArtifacts -**/*.Server/ModelManifest.xml -_Pvt_Extensions - -# Paket dependency manager -.paket/paket.exe -paket-files/ - -# FAKE - F# Make -.fake/ - -# CodeRush personal settings -.cr/personal - -# Python Tools for Visual Studio (PTVS) -__pycache__/ -*.pyc - -# Cake - Uncomment if you are using it -# tools/** -# !tools/packages.config - -# Tabs Studio -*.tss - -# Telerik's JustMock configuration file -*.jmconfig - -# BizTalk build output -*.btp.cs -*.btm.cs -*.odx.cs -*.xsd.cs - -# OpenCover UI analysis results -OpenCover/ - -# Azure Stream Analytics local run output -ASALocalRun/ - -# MSBuild Binary and Structured Log -*.binlog - -# NVidia Nsight GPU debugger configuration file -*.nvuser - -# MFractors (Xamarin productivity tool) working folder -.mfractor/ - -# Local History for Visual Studio -.localhistory/ - -# BeatPulse healthcheck temp database -healthchecksdb - -# Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ - -# Ionide (cross platform F# VS Code tools) working folder -.ionide/ - -# Fody - auto-generated XML schema -FodyWeavers.xsd \ No newline at end of file diff --git a/XPLPro_Plugin_Source/libconfig.lib b/XPLPro_Plugin_Source/libconfig.lib new file mode 100644 index 0000000000000000000000000000000000000000..841786e70091b7b69476db044dd379d737f5b5d2 GIT binary patch literal 17048 zcmd5?eQ;FO6+Z+Jj3IzuC?YHnLOvh~$?k>(5;ll4h=2@YrLA>cvYW8F$;M<;tW(;K zqry0?oldFa^bhMe*8b6{cBo_P=g=yYwv^&H1p*yu1zW#Bhl=C$W9T{W-uL#M`_6mW z4a-b-=Ind-o{!(X=broh<}ObRc5m%0Zw&F@;w3z7r<(LjxT#sc-c=3&4*|?M3ox$= zVE!Ed(Nl_A?*t%PP^~CBfcZ$vc4-RX6RGj2qRtEeQR`tv4HW=Hiyu?8s2zYPQl@Ch zasZ;PPDK$c1JUva6*cVvAnLeJQF9#t(TYQg!f2Z)wpLMiC#I2Vo>x?hU>Ah($~-) zQv1`2+Li(kE!nN89qT~UhH0V}^ruC$@rks!Mp5-n0HTHm6jgtYX`}}95z)f86;)%o zh!#DoXyM(MkJOk{RP_=7(Sj!xtwj4o^_vxSy@LKns^71u?hN|pOgw(mx(&B%+!SAR z7jU{w|6kro5-agi07w0)SbvA1_f2kV0y_^PhvQei>Ld$GsDSLyl1$- z+g25MOxr1Qe=>ESt;RD&`N33Q_N%FQDwFCnwcM-#U0F@`Xd;<3#VJd)j)jkJ&1Ua0 z6`XugE0gN)&22Sxbgro(`kL&sHt^L-rrmApC{eaYCz%?`4GwqbvP{L5Yid{#*o$T9 zOZ9C@xwTA=ucp+fWYNkOwW#h`P6~cW*<_102qD0R$rf!8(3WgA<6DY6Q`9Gryok|t zIaAap{GLoUp?zf-Fu0-x0`a$Ca77D*lJ3t%!@f>%aYYM+;*v3HVQ@tYx(q=jP&`pv zBZ%6J$Fwup=Z6QZ=Cix8J4=$a9Bl}zJW1Mei6O1>e5AdyynpNBsh~H6b*5mM3v!F- zcdM5x%eJJE%WT>_@@r3aurHA_wOkxgliFI=ba8w&dFAcWkf!7Tn@?quHC-HEOzPog zEeX-e7q!T$q~+v`T4a-jm|grl!&i?5n_EwaID;)!4Yh(IMXa1}@3Ha3_?4MrJ+;2* zBE}Q7$@ijao+0XK%c6rBZxn6Q&3Rqf(^M=GG|vzbHQR)<}D0)jShJ{qOCfzd9#LWxbO#Rk&+CI|p}! z^8oIc4{$09aAzy-AQu1(;QOv+03oEKjR2WWfWyeEXaIO@G45Iy0hC2>7rX>_x?N}o z-yg&s{GKL&`*1s4*9>rI1CbGguxx0D*B(2AyyTtblfi zKr1YVHkb>u;Ch$?vmpelpbKt*sjv*fPzh5Y3QMt=tGsG z!xbXB9nP_YCy?9#YULE9 zYj1diWJYm;J~HvO;1hOE4HQ2BByF9tiT2r{p`V0w{%3p1=d8-T9~8~{_I$^%+E@of zK)%QG{%%+ZXhUrw$ieDZQ3e?G$Pr5t&_ir)K+BOxfCn7*XeI*s0ND`7Agc+9>)S&# z(;ROx+pQbeL$rxe${*A~WWl!w2+Kv+a#XLo*|JwWyVipCtg4gF03~k&{PsG|?t}C_ z%X9b6LxrckUUl~vT>_n@B82Brqj_?$rFfoptj@G%L)W`^b-IsvO6wl;!a%W?CUBoao#0lg)L#sq;B2iW`djm4_vpF9aDaQ(Fj!a?@l4Fl7aNY4V$3-Ve>E}YNYCh{ z?(y98H;IeBaTvb%ez8cJvP<(EX4HE|pvJC%J5=X(wIP|w;4#2xH~o<&`%{3s%99U| zhf9XTC#R0X-8k-e>DQ1cnBcenuGwiEgpgJ~-p(#b?FQHA?;^}7-ue?mH` z)8p|O!`pf-hvx|DSBZ~th-b@DZVW`=BR7pmD<8(MqQ`kOVMJt{CoMIi#*e$(4D{GVvOF&v0>XZr@Qyd$}B!2_m1`yfRj^P;x49q*;F@LJ?C2A8s1=pO>uyQZeO-Nh+4}?}`{ap;14In4j1Q{iKK?S6qZh zD5Q0-M`+&<8H)B>oBef->S<5?<;8bTAb@IW*>3?o4Nt?=k9sQgH1{tCF}tVX37h(n z+z~sWpCoq?{9A}`=U@>6!m?QJhFf(|hUkkW>aNL$XYTsW@$0ObPOwLJwJ2uBq39kE zwL5?d>wE8w9K?e{JSB9n#5FgEW~l=DUbxL$%S)U8xt9X9%#DoG44!B+^JA!|JvF%M z`TaGw@5e)095$VLI;%t1hT#H{ogv1B{Be5U`yoW0z>)RJnFF#^0e+3Nc>Vg`y?=ja zF5*p;@P;nbw~>e!aouy1N9H5qB^)uo>}S;~zCFWHFXo$n44<2cm~CpyEws^bovrX{vQzM1iMyo)mPZ>Y+>K_lHY9I<3Gzcfc~`_?Z`Q7x}!n9g}3Yq-)x&*MM%)j5iu znO;QuSkeeuR)_+kCn}74$94~&#%p}Mb$7?CbI?aued^GKft9Al3tGN@f@(ZV#-lapA^FQ9w*bg>`qT;^!aWM^pHXlGu+GuH@{ZV@%owcRZ3hNOR#rFS@#U zVO1=CoR&^+I@(9xrP!(wFx?kB9GayH@U_&F-<~kz81>{@5m{dwF`(jWEUnF}U%u`< zt!u3o{MI#Gq zybmW;?xi(elP|J3SQbBC2~oY{^!9xe)l0nC`lgiCuq07EC)RO-qPp1+voxc#umk+; zmv4PSE7}$>GVSfH59cnhzC!!%I8y#!YTvLwYH4aLtfr&W&y3Ir9g(r6PF!?cNo%d~ z{d4!yS}PiWD^;3#e~cr@xrt94rxB#p2fHMzX(770o;z@eqHC#)dy&pkJ_~R7h}Q6J zGOBm5EV_NAng7k3fAmhKF~l`36yTT3^fFZ^`Ne!2l&kw;hG al(4FeVMQsl?T-^T9ta^;%)pWkwEqWNDjvlE literal 0 HcmV?d00001 From f5056588e3b7b7deb74107800d28b1f156c02439 Mon Sep 17 00:00:00 2001 From: GioCC Date: Thu, 14 Mar 2024 15:17:41 +0100 Subject: [PATCH 08/13] Update to status: 2024-03 (EXCEPT plugin sources!) Internal "XPLPro" folders added for file groups Demos moved under Arduino project (as per library convention) --- XPLPro_Arduino/XPLPro/XPLMux4067Switches.h | 196 ++++++ XPLPro_Arduino/XPLPro/XPLPotentiometers.h | 160 +++++ XPLPro_Arduino/{ => XPLPro}/XPLPro.cpp | 146 +++-- XPLPro_Arduino/{ => XPLPro}/XPLPro.h | 3 +- XPLPro_Arduino/{ => XPLPro}/XPLProManual.odt | Bin XPLPro_Arduino/XPLPro/XPLSwitches.h | 166 +++++ .../XPLProAbbreviationsDemo.ino | 0 .../XPLProAbbreviationsDemo2.ino | 238 +++++++ .../XPLProBeaconDemo/XPLProBeaconDemo.ino | 111 ++++ .../XPLProMax72XXExample.ino | 85 +++ .../XPLProMultiDemo}/XPLProMultiDemo.ino | 559 ++++++++--------- .../Multiplexer Wiring Diagram.jpg | Bin 0 -> 488195 bytes .../XPLProMultiplexerExample.ino | 101 +++ .../multiplexer wiring diagram.fzz | Bin 0 -> 6093 bytes .../XPLProParkingBrakeDemo.ino | 117 ++++ .../XPLProPotentiometersExample.ino | 93 +++ .../XPLProRadioBox/Circuit Layout.fzz | Bin 0 -> 40864 bytes .../XPLProRadioBox/Circuit Layout_bb.jpg | Bin 0 -> 615852 bytes .../XPLProRadioBox/XPLProRadioBox.ino | 579 ++++++++++++++++++ .../XPLProRadioSwapDemo.ino | 146 +++++ .../XPLProSequenceExample.ino | 175 ++++++ .../XPLProShutdownExample.ino | 84 +++ .../XPLProStringDemo}/XPLProStringDemo.ino | 0 .../XPLProSwitchesExample/Circuit Layout.fzz | Bin 0 -> 5051 bytes .../XPLProSwitchesExample/Circuit Layout.jpg | Bin 0 -> 438051 bytes .../XPLProSwitchesExample.ino | 102 +++ .../XPLProTutorialPart2.ino | 136 ++++ XPLPro_Arduino/{ => XPLPro}/readme.txt | 29 +- XPLPro_Plugin/64/libconfig.dll | Bin 54272 -> 0 bytes XPLPro_Plugin/64/win.xpl | Bin 40960 -> 0 bytes XPLPro_Plugin/XPLPro/64/win.xpl | Bin 0 -> 43520 bytes XPLPro_Plugin/{ => XPLPro}/XPLPro.cfg | 0 XPLPro_Plugin/{ => XPLPro}/abbreviations.txt | 0 33 files changed, 2901 insertions(+), 325 deletions(-) create mode 100644 XPLPro_Arduino/XPLPro/XPLMux4067Switches.h create mode 100644 XPLPro_Arduino/XPLPro/XPLPotentiometers.h rename XPLPro_Arduino/{ => XPLPro}/XPLPro.cpp (84%) rename XPLPro_Arduino/{ => XPLPro}/XPLPro.h (98%) rename XPLPro_Arduino/{ => XPLPro}/XPLProManual.odt (100%) create mode 100644 XPLPro_Arduino/XPLPro/XPLSwitches.h rename {XPLPro_Demo => XPLPro_Arduino/XPLPro/examples/XPLProAbbreviationsDemo}/XPLProAbbreviationsDemo.ino (100%) create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProAbbreviationsDemo2/XPLProAbbreviationsDemo2.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProBeaconDemo/XPLProBeaconDemo.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProMax72XXExample/XPLProMax72XXExample.ino rename {XPLPro_Demo => XPLPro_Arduino/XPLPro/examples/XPLProMultiDemo}/XPLProMultiDemo.ino (92%) create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProMultiplexerExample/Multiplexer Wiring Diagram.jpg create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProMultiplexerExample/XPLProMultiplexerExample.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProMultiplexerExample/multiplexer wiring diagram.fzz create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProParkingBrakeDemo/XPLProParkingBrakeDemo.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProPotentiometersExample/XPLProPotentiometersExample.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProRadioBox/Circuit Layout.fzz create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProRadioBox/Circuit Layout_bb.jpg create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProRadioBox/XPLProRadioBox.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProRadioSwapDemo/XPLProRadioSwapDemo.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProSequenceExample/XPLProSequenceExample.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProShutdownExample/XPLProShutdownExample.ino rename {XPLPro_Demo => XPLPro_Arduino/XPLPro/examples/XPLProStringDemo}/XPLProStringDemo.ino (100%) create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProSwitchesExample/Circuit Layout.fzz create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProSwitchesExample/Circuit Layout.jpg create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProSwitchesExample/XPLProSwitchesExample.ino create mode 100644 XPLPro_Arduino/XPLPro/examples/XPLProTutorialPart2/XPLProTutorialPart2.ino rename XPLPro_Arduino/{ => XPLPro}/readme.txt (50%) delete mode 100644 XPLPro_Plugin/64/libconfig.dll delete mode 100644 XPLPro_Plugin/64/win.xpl create mode 100644 XPLPro_Plugin/XPLPro/64/win.xpl rename XPLPro_Plugin/{ => XPLPro}/XPLPro.cfg (100%) rename XPLPro_Plugin/{ => XPLPro}/abbreviations.txt (100%) diff --git a/XPLPro_Arduino/XPLPro/XPLMux4067Switches.h b/XPLPro_Arduino/XPLPro/XPLMux4067Switches.h new file mode 100644 index 0000000..27304a7 --- /dev/null +++ b/XPLPro_Arduino/XPLPro/XPLMux4067Switches.h @@ -0,0 +1,196 @@ +// XPLMux4067Switches.h - Library for 4067 multiplexer +// Created by Curiosity Workshop, Michael Gerlicher, 2024 +// +// To report problems, download updates and examples, suggest enhancements or get technical support, please visit: +// discord: https://discord.gg/gzXetjEST4 +// patreon: www.patreon.com/curiosityworkshop + +#ifndef XPLMux4067Switches_h +#define XPLMux4067Switches_h + +// Parameters around the interface +#define XPLMUX4067_DEBOUNCETIME 50 +#define XPLMUX4067_PRESSED 0 +#define XPLMUX4067_RELEASED 1 + +#define XPLMUX4067_SENDTOHANDLER 0 // Default is to send switch events to the supplied handler. This always occurs regardless. +#define XPLMUX4067_DATAREFWRITE 1 // Update dataref with switch status +#define XPLMUX4067_COMMANDTRIGGER 2 // Trigger command with pressed +#define XPLMUX4067_COMMANDSTARTEND 3 // Start command when pressed, end command when released +#define XPLMUX4067_DATAREFWRITE_INVERT 4 // same as datarefwrite but invert the signal + +/// @brief Core class for the XPLPro Arduino library +class XPLMux4067Switches +{ +public: + /// @brief Constructor + /// @param inPinSig Pin connection for reading + /// @param inPinS0, Pin connection for s0 + /// @param inPinS1, Pin connection for s1 + /// @param inPinS2, Pin connection for s2 + /// @param inPinS3, Pin connection for s3 + /// @param muxHandler, function called when pin activity is detected, or NULL + XPLMux4067Switches(int inPinSig, int inPinS0, int inPinS1, int inPinS2, int inPinS3, void (*muxHandler)(int muxChannel, int muxValue)); + + void begin(XPLPro* xplpro); + + int addPin(int inPin, byte inMode, int inHandle); + + int getHandle(int inPin); + + + /// @brief Scan mux pins and call handler if any changes are detected. Run regularly + void check(void); + + void clear(void); + +private: + + XPLPro* _XP; + int _maxSwitches; + int _switchCount; + + void (*_muxHandler)(int muxChannel, int muxValue) = NULL; // this function will be called when activity is detected on the mux + + int _pinS0; + int _pinS1; + int _pinS2; + int _pinS3; + int _pinSig; + + int _muxChannel[16][4]= // this table reduces processing time and space + { + {0,0,0,0}, //channel 0 + {1,0,0,0}, //channel 1 + {0,1,0,0}, //channel 2 + {1,1,0,0}, //channel 3 + {0,0,1,0}, //channel 4 + {1,0,1,0}, //channel 5 + {0,1,1,0}, //channel 6 + {1,1,1,0}, //channel 7 + {0,0,0,1}, //channel 8 + {1,0,0,1}, //channel 9 + {0,1,0,1}, //channel 10 + {1,1,0,1}, //channel 11 + {0,0,1,1}, //channel 12 + {1,0,1,1}, //channel 13 + {0,1,1,1}, //channel 14 + {1,1,1,1} //channel 15 + }; + + struct XPLSwitch + { + int muxPin; // connected pin + byte prevStatus; // last known status + byte mode; + int handle; + long int prevTime; // time of last change + + }; + + struct XPLSwitch _switches[16]; + // struct XPLSwitch _switches[]; +}; + + +XPLMux4067Switches::XPLMux4067Switches(int inPinSig, int inPinS0, int inPinS1, int inPinS2, int inPinS3, void (*muxHandler)(int inChannel, int inValue)) +{ + + _pinSig = inPinSig; pinMode(_pinSig, INPUT_PULLUP); + _pinS0 = inPinS0; pinMode(_pinS0, OUTPUT); digitalWrite(_pinS0, LOW); + _pinS1 = inPinS1; pinMode(_pinS1, OUTPUT); digitalWrite(_pinS1, LOW); + _pinS2 = inPinS2; pinMode(_pinS2, OUTPUT); digitalWrite(_pinS2, LOW); + _pinS3 = inPinS3; pinMode(_pinS3, OUTPUT); digitalWrite(_pinS3, LOW); + + _muxHandler = muxHandler; + // _maxSwitches = inMaxSwitches; + // if (_maxSwitches > 16) _maxSwitches = 16; // max for 4067 mux + _maxSwitches = 16; // my intention is to make this dynamic but it is problematic + //switches = new struct XPLSwitch[ _maxSwitches]; + +}; + +void XPLMux4067Switches::begin(XPLPro* xplpro) +{ + _XP = xplpro; + clear(); + +} + +void XPLMux4067Switches::clear(void) // call this prior to adding pins if not the first run +{ + _switchCount = 0; + +} + +int XPLMux4067Switches::addPin(int inPin, byte inMode, int inHandle) +{ + if (_switchCount >= _maxSwitches) return -1; + + _switches[_switchCount].muxPin = inPin; + _switches[_switchCount].mode = inMode; + _switches[_switchCount].handle = inHandle; + _switches[_switchCount].prevStatus = -1; // this will force it to update to the plugin. + + return _switchCount++; + +} + +int XPLMux4067Switches::getHandle(int inPin) +{ + for (int i = 0; i < _maxSwitches; i++) if (_switches[i].muxPin == inPin) return _switches[i].handle; + return -1; + +} + + +void XPLMux4067Switches::check(void) +{ + + long int timeNow = millis(); + for (int i = 0; i < _switchCount; i++) + { + digitalWrite(_pinS0, _muxChannel[_switches[i].muxPin][0]); + digitalWrite(_pinS1, _muxChannel[_switches[i].muxPin][1]); + digitalWrite(_pinS2, _muxChannel[_switches[i].muxPin][2]); + digitalWrite(_pinS3, _muxChannel[_switches[i].muxPin][3]); + + int pinValue = digitalRead(_pinSig); + + if (pinValue != _switches[i].prevStatus && timeNow - _switches[i].prevTime >= XPLMUX4067_DEBOUNCETIME) + { + _switches[i].prevStatus = pinValue; + _switches[i].prevTime = timeNow; + + switch (_switches[i].mode) + { + + case XPLMUX4067_DATAREFWRITE: + _XP->datarefWrite(_switches[i].handle, pinValue); + break; + + case XPLMUX4067_DATAREFWRITE_INVERT: + _XP->datarefWrite(_switches[i].handle, !pinValue); + break; + + case XPLMUX4067_COMMANDTRIGGER: + if (pinValue == XPLMUX4067_PRESSED) _XP->commandTrigger(_switches[i].handle); + break; + + case XPLMUX4067_COMMANDSTARTEND: + if (pinValue == XPLMUX4067_PRESSED) _XP->commandStart(_switches[i].handle); + if (pinValue == XPLMUX4067_RELEASED) _XP->commandEnd(_switches[i].handle); + break; + + + } + + + if (_muxHandler != NULL) _muxHandler(_switches[i].muxPin, pinValue); + } + + } + +} + +#endif \ No newline at end of file diff --git a/XPLPro_Arduino/XPLPro/XPLPotentiometers.h b/XPLPro_Arduino/XPLPro/XPLPotentiometers.h new file mode 100644 index 0000000..eac8a31 --- /dev/null +++ b/XPLPro_Arduino/XPLPro/XPLPotentiometers.h @@ -0,0 +1,160 @@ +// XPLPotentiometers.h - XPLPro Add-on Library for simple potentiometer connections +// Created by Curiosity Workshop, Michael Gerlicher, 2024 +// +// To report problems, download updates and examples, suggest enhancements or get technical support, please visit: +// discord: https://discord.gg/gzXetjEST4 +// patreon: www.patreon.com/curiosityworkshop + +#ifndef XPLSwitches_h +#define XPLSwitches_h + +// Parameters around the interface +#define XPLPOTS_SENDTOHANDLER 0 // Default is to send switch events to the supplied handler. This always occurs regardless. +#define XPLPOTS_DATAREFWRITE 1 // Update dataref with switch status + +#define XPLPOTS_UPDATERATE 50 // default minimum time between updates in milliseconds + + +#ifndef XPLPOTS_MAXPOTS + #define XPLPOTS_MAXPOTS 10 //Default to 10. +#endif + + +/// @brief Core class for the XPLPro Potentiometers Addon +class XPLPotentiometers +{ +public: + /// @brief Constructor + /// @param potHandler, Function called when pot activity detected, or NULL if not needed + XPLPotentiometers(void (*potHandler)(int pin, float potValue)); + + /// + /// @brief begin + /// + /// + void begin(XPLPro *xplpro); + + int addPin(int inPin, int inMode, int inHandle, int inPrecision, int inLow, int inHigh, int outLow, int outHigh); + void setUpdateRate(int inRate); + int getHandle(int inPin); + + + /// @brief Scan pins and call handler if any changes are detected. Run regularly + void check(void); + + void clear(void); + +private: + + XPLPro* _XP; + + int _potCount; // how many are registered + int _updateRate; // in milliseconds + + + void (*_potHandler)(int inSwitchID, float inPotValue) = NULL; // this function will be called when activity is detected on the pot, if not NULL + + + struct XPLPot + { + int arduinoPin; // connected pin + int prevValue; // last known value + int handle; // handle to dataref + int mode; // what to do with new data + long int prevTime; // time of last change + int precision; // divide by this to reduce data flow + + }; + + struct XPLPot _pots[XPLPOTS_MAXPOTS]; + +}; + + +XPLPotentiometers::XPLPotentiometers(void (*potHandler)(int inPotID, float inValue)) +{ + + _potHandler = potHandler; + _updateRate = XPLPOTS_UPDATERATE; + + +}; + +void XPLPotentiometers::begin(XPLPro* xplpro) +{ + _XP = xplpro; + clear(); + +} + +void XPLPotentiometers::clear(void) // call this prior to adding pins if not the first run +{ + _potCount = 0; + +} + +void XPLPotentiometers::setUpdateRate(int inRate) +{ + _updateRate = inRate; +} + +int XPLPotentiometers::addPin(int inPin, int inMode, int inHandle, int inPrecision, int inLow, int inHigh, int outLow, int outHigh) +{ + if (_potCount >= XPLPOTS_MAXPOTS) return -1; + + _pots[_potCount].arduinoPin = inPin; + _pots[_potCount].precision = inPrecision; + _pots[_potCount].mode = inMode; + _pots[_potCount].handle = inHandle; + _pots[_potCount].prevValue = -1; // This will force update to the plugin + + _XP->setScaling(inHandle, inLow, inHigh, outLow, outHigh); + + return _potCount++; + + +} +int XPLPotentiometers::getHandle(int inPin) +{ + for (int i = 0; i < XPLPOTS_MAXPOTS; i++) if (_pots[i].arduinoPin == inPin) return _pots[i].handle; + return -1; + +} + + +void XPLPotentiometers::check(void) +{ + + unsigned long timeNow = millis(); + + + for (int i = 0; i < _potCount; i++) + { + int pinValue = analogRead(_pots[i].arduinoPin); + + if (_pots[i].precision) pinValue = ((int)(pinValue / _pots[i].precision) * _pots[i].precision); + + if (pinValue != _pots[i].prevValue && timeNow - _pots[i].prevTime >= XPLPOTS_UPDATERATE) + { + + _pots[i].prevValue = pinValue; + _pots[i].prevTime = timeNow; + + switch (_pots[i].mode) + { + + case XPLPOTS_DATAREFWRITE: + _XP->datarefWrite(_pots[i].handle, pinValue); + break; + + + } + + if (_potHandler != NULL) _potHandler(_pots[i].arduinoPin, pinValue); + + } + } + +} + +#endif \ No newline at end of file diff --git a/XPLPro_Arduino/XPLPro.cpp b/XPLPro_Arduino/XPLPro/XPLPro.cpp similarity index 84% rename from XPLPro_Arduino/XPLPro.cpp rename to XPLPro_Arduino/XPLPro/XPLPro.cpp index 3b41454..f0a853f 100644 --- a/XPLPro_Arduino/XPLPro.cpp +++ b/XPLPro_Arduino/XPLPro/XPLPro.cpp @@ -142,6 +142,7 @@ void XPLPro::datarefWrite(int handle, float value) return; } char tBuf[20]; // todo: rewrite to eliminate this buffer. Write directly to _sendBuffer + Xdtostrf(value, 0, XPL_FLOATPRECISION, tBuf); sprintf(_sendBuffer, "%c%c,%i,%s%c", XPL_PACKETHEADER, @@ -179,6 +180,17 @@ void XPLPro::_sendname() } } +void XPLPro::_sendVersion() +{ + // register device on request only when we have a valid name + if (_deviceName != NULL) + { + char version[25]; + sprintf(version, "%s %s", __DATE__, __TIME__); + _sendPacketString(XPLRESPONSE_VERSION, version); + } +} + void XPLPro::sendResetRequest() { // request a reset only when we have a valid name @@ -241,9 +253,11 @@ void XPLPro::_processPacket() // register device case XPLCMD_SENDNAME: + _sendVersion(); _sendname(); _connectionStatus = true; // not considered active till you know my name _registerFlag = 0; + break; // plugin is ready for registrations. @@ -305,7 +319,7 @@ void XPLPro::_processPacket() _xplInboundHandler(&_inData); break; - + // obsolete? reserve for the time being... // case XPLREQUEST_REFRESH: @@ -345,82 +359,118 @@ void XPLPro::_transmitPacket(void) } } -int XPLPro::_parseString(char *outBuffer, char *inBuffer, int parameter, int maxSize) +int XPLPro::_parseString(char *outBuffer, char *inBuffer, int parameter, int maxSize)// todo: Confirm 0 length strings ("") dont cause issues { - // todo: Confirm 0 length strings ("") dont cause issues int cBeg; int pos = 0; int len; - for (int i = 1; i < parameter; i++) { - while (inBuffer[pos] != ',' && inBuffer[pos] != 0) pos++; - if(inBuffer[pos] != 0) pos++; + for (int i = 1; i < parameter; i++) + { + while (inBuffer[pos] != ',' && inBuffer[pos] != 0) + { + pos++; + } + pos++; } - while (inBuffer[pos] != '\"' && inBuffer[pos] != 0) pos++; - if(inBuffer[pos] != 0) ++pos; - cBeg = pos; - - while (inBuffer[pos] != '\"' && inBuffer[pos] != 0) pos++; + while (inBuffer[pos] != '\"' && inBuffer[pos] != 0) + { + pos++; + } + cBeg = ++pos; + while (inBuffer[pos] != '\"' && inBuffer[pos] != 0) + { + pos++; + } len = pos - cBeg; - if (len > maxSize) len = maxSize; - + if (len > maxSize) + { + len = maxSize; + } strncpy(outBuffer, (char *)&inBuffer[cBeg], len); outBuffer[len] = 0; // fprintf(errlog, "_parseString, pos: %i, cBeg: %i, deviceName: %s\n", pos, cBeg, target); return 0; } -void XPLPro::_seekParm(const char* buf, int paramIdx, int& start, int &end) +int XPLPro::_parseInt(int *outTarget, char *inBuffer, int parameter) { + int cBeg; int pos = 0; // search for the selected parameter - for (int i = 1; i < paramIdx; i++) { - while (buf[pos] != ',' && buf[pos] != 0) pos++; - if(buf[pos] != 0)pos++; // skip separator + for (int i = 1; i < parameter; i++) + { + while (inBuffer[pos] != ',' && inBuffer[pos] != 0) + { + pos++; + } + pos++; } // parameter starts here - start = pos; + cBeg = pos; // search for end of parameter - while (buf[pos] != ',' && buf[pos] != 0 && buf[pos] != XPL_PACKETTRAILER) pos++; - end = pos; -} - - -int XPLPro::_parseInt(int *outTarget, char *inBuffer, int parameter) -{ - int cSt, cEnd; - _seekParm(inBuffer, parameter, cSt, cEnd); + while (inBuffer[pos] != ',' && inBuffer[pos] != 0 && inBuffer[pos] != XPL_PACKETTRAILER) + { + pos++; + } // temporarily make parameter null terminated - char holdChar = inBuffer[cEnd]; - inBuffer[cEnd] = 0; + char holdChar = inBuffer[pos]; + inBuffer[pos] = 0; // get integer value from string - *outTarget = atoi((char *)&inBuffer[cSt]); + *outTarget = atoi((char *)&inBuffer[cBeg]); // restore buffer - inBuffer[cEnd] = holdChar; + inBuffer[pos] = holdChar; return 0; } int XPLPro::_parseInt(long *outTarget, char *inBuffer, int parameter) { - int cSt, cEnd; - _seekParm(inBuffer, parameter, cSt, cEnd); - char holdChar = inBuffer[cEnd]; - inBuffer[cEnd] = 0; - *outTarget = atol((char *)&inBuffer[cSt]); - inBuffer[cEnd] = holdChar; + int cBeg; + int pos = 0; + for (int i = 1; i < parameter; i++) + { + while (inBuffer[pos] != ',' && inBuffer[pos] != 0) + { + pos++; + } + pos++; + } + cBeg = pos; + while (inBuffer[pos] != ',' && inBuffer[pos] != 0 && inBuffer[pos] != XPL_PACKETTRAILER) + { + pos++; + } + char holdChar = inBuffer[pos]; + inBuffer[pos] = 0; + *outTarget = atol((char *)&inBuffer[cBeg]); + inBuffer[pos] = holdChar; return 0; } int XPLPro::_parseFloat(float *outTarget, char *inBuffer, int parameter) { - int cSt, cEnd; - _seekParm(inBuffer, parameter, cSt, cEnd); - char holdChar = inBuffer[cEnd]; - inBuffer[cEnd] = 0; - *outTarget = atof((char *)&inBuffer[cSt]); - inBuffer[cEnd] = holdChar; + int cBeg; + int pos = 0; + for (int i = 1; i < parameter; i++) + { + while (inBuffer[pos] != ',' && inBuffer[pos] != 0) + { + pos++; + } + pos++; + } + cBeg = pos; + while (inBuffer[pos] != ',' && inBuffer[pos] != 0 && inBuffer[pos] != XPL_PACKETTRAILER) + { + pos++; + } + char holdChar = inBuffer[pos]; + inBuffer[pos] = 0; + *outTarget = atof((char *)&inBuffer[cBeg]); + inBuffer[pos] = holdChar; + return 0; } int XPLPro::registerDataRef(XPString_t *datarefName) @@ -508,10 +558,16 @@ void XPLPro::setScaling(int handle, int inLow, int inHigh, int outLow, int outHi _transmitPacket(); } // Re-creation of dtostrf for non-AVR boards -char* Xdtostrf(double val, signed char width, unsigned char prec, char* sout) +char *XPLPro::Xdtostrf(double val, signed char width, unsigned char prec, char* sout) { +#ifdef __AVR_ARCH__ + return dtostrf(val, width, prec, sout); +#else char fmt[20]; sprintf(fmt, "%%%d.%df", width, prec); sprintf(sout, fmt, val); return sout; -} \ No newline at end of file +#endif + +} + diff --git a/XPLPro_Arduino/XPLPro.h b/XPLPro_Arduino/XPLPro/XPLPro.h similarity index 98% rename from XPLPro_Arduino/XPLPro.h rename to XPLPro_Arduino/XPLPro/XPLPro.h index d0bf612..c2d90e9 100644 --- a/XPLPro_Arduino/XPLPro.h +++ b/XPLPro_Arduino/XPLPro/XPLPro.h @@ -77,6 +77,7 @@ typedef const char XPString_t; // Items in caps generally come from XPlane. Items in lower case are generally sent from the arduino. #define XPLCMD_SENDNAME 'N' // plugin request name from arduino #define XPLRESPONSE_NAME 'n' // Arduino responds with device name as initialized in the "begin" function +#define XPLRESPONSE_VERSION 'v' // Arduino responds with build date and time (when sketch was compiled) #define XPLCMD_SENDREQUEST 'Q' // plugin sends this when it is ready to register bindings #define XPLCMD_FLIGHTLOOPPAUSE 'p' // stop flight loop while we register #define XPLCMD_FLIGHTLOOPRESUME 'q' // @@ -241,9 +242,9 @@ class XPLPro void _processPacket(); void _transmitPacket(); void _sendname(); + void _sendVersion(); void _sendPacketVoid(int command, int handle); // just a command with a handle void _sendPacketString(int command, const char *str); // send a string - void _seekParm(char* buf, int paramIdx, int& start, int &end); int _parseInt(int *outTarget, char *inBuffer, int parameter); int _parseInt(long *outTarget, char *inBuffer, int parameter); int _parseFloat(float *outTarget, char *inBuffer, int parameter); diff --git a/XPLPro_Arduino/XPLProManual.odt b/XPLPro_Arduino/XPLPro/XPLProManual.odt similarity index 100% rename from XPLPro_Arduino/XPLProManual.odt rename to XPLPro_Arduino/XPLPro/XPLProManual.odt diff --git a/XPLPro_Arduino/XPLPro/XPLSwitches.h b/XPLPro_Arduino/XPLPro/XPLSwitches.h new file mode 100644 index 0000000..223eaaa --- /dev/null +++ b/XPLPro_Arduino/XPLPro/XPLSwitches.h @@ -0,0 +1,166 @@ +// XPLSwitches.h - XPLPro Add-on Library for simple switch connections +// Created by Curiosity Workshop, Michael Gerlicher, 2024 +// +// To report problems, download updates and examples, suggest enhancements or get technical support, please visit: +// discord: https://discord.gg/gzXetjEST4 +// patreon: www.patreon.com/curiosityworkshop + +#ifndef XPLSwitches_h +#define XPLSwitches_h + +// Parameters around the interface +#define XPLSWITCHES_SENDTOHANDLER 0 // Default is to send switch events to the supplied handler. This always occurs regardless. +#define XPLSWITCHES_DATAREFWRITE 1 // Update dataref with switch status +#define XPLSWITCHES_COMMANDTRIGGER 2 // Trigger command with pressed +#define XPLSWITCHES_COMMANDSTARTEND 3 // Start command when pressed, end command when released +#define XPLSWITCHES_DATAREFWRITE_INVERT 4 // same as datarefwrite but invert the signal + +#define XPLSWITCHES_DEBOUNCETIME 50 +#define XPLSWITCHES_PRESSED 0 +#define XPLSWITCHES_RELEASED 1 + +#ifndef XPLSWITCHES_MAXSWITCHES + #define XPLSWITCHES_MAXSWITCHES 40 //Default to 40. This costs ~400 bytes. +#endif + + +/// @brief Core class for the XPLPro Switches Addon +class XPLSwitches +{ +public: + /// @brief Constructor + /// @param switchHandler, Function called when pin activity is detected, or NULL if not needed + XPLSwitches(void (*switchHandler)(int pin, int switchValue)); + + /// + /// @brief begin + /// + /// + void begin(XPLPro *xplpro); + + int addPin(int inPin, byte inMode, int inHandle); + + int getHandle(int inPin); + + + /// @brief Scan pins and call handler if any changes are detected. Run regularly + void check(void); + + void clear(void); + +private: + + XPLPro* _XP; + + int _switchCount; // how many are registered + + + void (*_switchHandler)(int inSwitchID, int inSwitchValue) = NULL; // this function will be called when activity is detected on the mux, if not NULL + + + struct XPLSwitch + { + int arduinoPin; // connected pin + byte prevStatus; // last known status + byte mode; + int handle; + long int prevTime; // time of last change + + }; + + struct XPLSwitch _switches[XPLSWITCHES_MAXSWITCHES]; + +}; + + +XPLSwitches::XPLSwitches(void (*switchHandler)(int inSwitchID, int inValue)) +{ + + + _switchHandler = switchHandler; + + +}; + +void XPLSwitches::begin(XPLPro* xplpro) +{ + _XP = xplpro; + clear(); + +} + +void XPLSwitches::clear(void) // call this prior to adding pins if not the first run +{ + _switchCount = 0; + +} + +int XPLSwitches::addPin(int inPin, byte inMode, int inHandle) +{ + if (_switchCount >= XPLSWITCHES_MAXSWITCHES) return -1; + + _switches[_switchCount].arduinoPin = inPin; + _switches[_switchCount].mode = inMode; + _switches[_switchCount].handle = inHandle; + _switches[_switchCount].prevStatus = -1; // This will force update to the plugin + pinMode(inPin, INPUT_PULLUP); + + return _switchCount++; + + +} +int XPLSwitches::getHandle(int inPin) +{ + for (int i = 0; i < XPLSWITCHES_MAXSWITCHES; i++) if (_switches[i].arduinoPin == inPin) return _switches[i].handle; + return -1; + +} + + +void XPLSwitches::check(void) +{ + + unsigned long timeNow = millis(); + + + for (int i = 0; i < _switchCount; i++) + { + int pinValue = digitalRead(_switches[i].arduinoPin); + + if (pinValue != _switches[i].prevStatus && timeNow - _switches[i].prevTime >= XPLSWITCHES_DEBOUNCETIME) + { + + _switches[i].prevStatus = pinValue; + _switches[i].prevTime = timeNow; + + switch (_switches[i].mode) + { + + case XPLSWITCHES_DATAREFWRITE: + _XP->datarefWrite(_switches[i].handle, pinValue); + break; + + case XPLSWITCHES_DATAREFWRITE_INVERT: + _XP->datarefWrite(_switches[i].handle, !pinValue); + break; + + case XPLSWITCHES_COMMANDTRIGGER: + if (pinValue == XPLSWITCHES_PRESSED) _XP->commandTrigger(_switches[i].handle); + break; + + case XPLSWITCHES_COMMANDSTARTEND: + if (pinValue == XPLSWITCHES_PRESSED) _XP->commandStart(_switches[i].handle); + if (pinValue == XPLSWITCHES_RELEASED) _XP->commandEnd(_switches[i].handle); + break; + + + } + + if (_switchHandler != NULL) _switchHandler(_switches[i].arduinoPin, pinValue); + + } + } + +} + +#endif \ No newline at end of file diff --git a/XPLPro_Demo/XPLProAbbreviationsDemo.ino b/XPLPro_Arduino/XPLPro/examples/XPLProAbbreviationsDemo/XPLProAbbreviationsDemo.ino similarity index 100% rename from XPLPro_Demo/XPLProAbbreviationsDemo.ino rename to XPLPro_Arduino/XPLPro/examples/XPLProAbbreviationsDemo/XPLProAbbreviationsDemo.ino diff --git a/XPLPro_Arduino/XPLPro/examples/XPLProAbbreviationsDemo2/XPLProAbbreviationsDemo2.ino b/XPLPro_Arduino/XPLPro/examples/XPLProAbbreviationsDemo2/XPLProAbbreviationsDemo2.ino new file mode 100644 index 0000000..2b88e1c --- /dev/null +++ b/XPLPro_Arduino/XPLPro/examples/XPLProAbbreviationsDemo2/XPLProAbbreviationsDemo2.ino @@ -0,0 +1,238 @@ + +// ARDUINO MEGA + + +#include +#include // include file for the X-plane direct interface +#include + +XPLPro XP(&Serial); // create an instance of it +LiquidCrystal_I2C lcd(0x26,16,2); + +unsigned long startTime; // for timing purposes +bool baroMode; +bool alt1000Mode; + +// =============================== Rotary Encoder vars ====================================================================== +bool RE1_lastStateCLK; bool RE1_lastStateDT; bool RE1_lastStateSW; const int RE1_CLK = 22; const int RE1_DT = 23; const int RE1_SW = 30; +bool RE2_lastStateCLK; bool RE2_lastStateDT; bool RE2_lastStateSW; const int RE2_CLK = 24; const int RE2_DT = 25; const int RE2_SW = 31; +bool RE3_lastStateCLK; bool RE3_lastStateDT; bool RE3_lastStateSW; const int RE3_CLK = 26; const int RE3_DT = 27; const int RE3_SW = 32; + +// ================================== LIGHTS STATUS ========================================================================= +long int beacon; long int landing; long int taxi; long int navLights; long int strobes; + +// ================================== C O M M A N D S ======================================================================= +int cmdBcnToggle; int cmdLandToggle; int cmdTaxiToggle; int cmdNavToggle; int cmdStrobeToggle; +int cmdBattToggle; int cmdAvioToggle; int cmdGenToggle; + +int cmdHeadUp; int cmdHeadDown; int cmdHeadSync; // on Rotaly Encoder 1 +int cmdAltUp; int cmdAltDown; int cmdBaroUp; int cmdBaroDown; // on Rotary Encoder 2 +int cmdAlt100_Up; int cmdAlt100_Down; int cmdAlt1000_Up; int cmdAlt1000_Down; // on Rotary Encoder 2 v.2 +int cmdCrsUp; int cmdCrsDown; // on Rotary Encoder 3 + +// ===================================== pin LEDs and SWITCHES ============================================================ +bool beaconStatus; bool beaconLastStatus = true; const int beaconLed = 12; const int beaconSwitch = 6; +bool landingStatus; bool landingLastStatus = true; const int landingLed = 11; const int landingSwitch = 5; +bool taxiStatus; bool taxiLastStatus = true; const int taxiLed = 10; const int taxiSwitch = 4; +bool navLightsStatus; bool navLightsLastStatus = true; const int navLightsLed = 9; const int navLightsSwitch = 3; +bool strobesStatus; bool strobesLastStatus = true; const int strobesLed = 8; const int strobesSwitch = 2; + +bool battStatus; bool battLastStatus = true; const int battSwitch = 48; +bool avioStatus; bool avioLastStatus = true; const int avioSwitch = 49; +bool geneStatus; bool geneLastStatus = true; const int geneSwitch = 50; + +// ======================================= END of VARs DECLARIATIONs and DEFINITIONs ======================================= + + +void setup() +{ + + lcd.init(); + lcd.backlight(); + lcd.setCursor(0,0); + lcd.print("initializing.."); + + pinMode(RE1_CLK,INPUT); pinMode(RE1_DT,INPUT); pinMode(RE1_SW,INPUT_PULLUP); + pinMode(RE2_CLK,INPUT); pinMode(RE2_DT,INPUT); pinMode(RE2_SW,INPUT_PULLUP); + +// ------------- SWITCHes -------------------- + pinMode(beaconSwitch, INPUT_PULLUP); + pinMode(landingSwitch, INPUT_PULLUP); + pinMode(navLightsSwitch, INPUT_PULLUP); + pinMode(strobesSwitch, INPUT_PULLUP); + pinMode(taxiSwitch, INPUT_PULLUP); + pinMode(battSwitch, INPUT_PULLUP); + pinMode(avioSwitch, INPUT_PULLUP); + pinMode(geneSwitch, INPUT_PULLUP); + +// --------------- LEDs ---------------------- + pinMode(beaconLed, OUTPUT); + pinMode(landingLed, OUTPUT); + pinMode(navLightsLed, OUTPUT); + pinMode(strobesLed, OUTPUT); + pinMode(taxiLed, OUTPUT); + + Serial.begin(XPL_BAUDRATE); // start serial interface. Baudrate is specified in the header, dont change + + XP.begin("XPLPro Giorgio Lights & Switches", &xplRegister, &xplShutdown, &xplInboundHandler); + ErrorBlink(LED_BUILTIN, 5); // let everyone know we are awake + + while (!Serial) + { + ErrorBlink(LED_BUILTIN, 2); + delay(300); + } + + digitalWrite(beaconLed, LOW); + digitalWrite(landingLed, LOW); + digitalWrite(navLightsLed, LOW); + digitalWrite(strobesLed, LOW); + digitalWrite(taxiLed, LOW); + + RE1_lastStateCLK = digitalRead(RE1_CLK); RE1_lastStateDT = digitalRead(RE1_DT); RE1_lastStateSW = digitalRead(RE1_SW); + RE2_lastStateCLK = digitalRead(RE2_CLK); RE2_lastStateDT = digitalRead(RE2_DT); RE2_lastStateSW = digitalRead(RE2_SW); + RE3_lastStateCLK = digitalRead(RE3_CLK); RE3_lastStateDT = digitalRead(RE3_DT); RE3_lastStateSW = digitalRead(RE3_SW); + baroMode = false; + alt1000Mode = false; +} + + +void loop() +{ + XP.xloop(); + +// Rotary Encoders: 1 = Heading + Head Sync 2 = Altitude ( + Altitude x 1000 on G1000) 3 = Cursor + Barometer +// ======================================================================================================================= + checkRotaryEnc(1, RE1_CLK, RE1_DT, RE1_lastStateCLK, RE1_lastStateDT, cmdHeadDown, cmdHeadUp, RE1_SW, RE1_lastStateSW, cmdHeadSync); + if (!alt1000Mode) checkRotaryEnc(2, RE2_CLK, RE2_DT, RE2_lastStateCLK, RE2_lastStateDT, cmdAltDown, cmdAltUp, RE2_SW, RE2_lastStateSW, 3); + else checkRotaryEnc(2, RE2_CLK, RE2_DT, RE2_lastStateCLK, RE2_lastStateDT, cmdAlt1000_Down, cmdAlt1000_Up, RE2_SW, RE2_lastStateSW, 3); + if (!baroMode) checkRotaryEnc(3, RE3_CLK, RE3_DT, RE3_lastStateCLK, RE3_lastStateDT, cmdCrsDown, cmdCrsUp, RE3_SW, RE3_lastStateSW, 3); + else checkRotaryEnc(3, RE3_CLK, RE3_DT, RE3_lastStateCLK, RE3_lastStateDT, cmdBaroDown, cmdBaroUp, RE3_SW, RE3_lastStateSW, 3); + + if (millis() - startTime > 100) startTime = millis(); else return; + + checkStatus(beaconSwitch, beaconLastStatus, cmdBcnToggle); + checkStatus(landingSwitch, landingLastStatus, cmdLandToggle); + checkStatus(taxiSwitch, taxiLastStatus, cmdTaxiToggle); + checkStatus(navLightsSwitch, navLightsLastStatus, cmdNavToggle); + checkStatus(strobesSwitch, strobesLastStatus, cmdStrobeToggle); + checkStatus(battSwitch, battLastStatus, cmdBattToggle); + checkStatus(avioSwitch, avioLastStatus, cmdAvioToggle); + checkStatus(geneSwitch, geneLastStatus, cmdGenToggle); +} + +void checkRotaryEnc(int devNum, int pinA, int pinB, bool& lastA, bool& lastB, int cmdCode1, int cmdCode2, int pinSw, bool& lastSw, int cmdCode3) { + bool flagA = !digitalRead(pinA); + bool flagB = !digitalRead(pinB); + if (flagA != lastA) { + if(flagB == flagA) XP.commandTrigger(cmdCode1); + else XP.commandTrigger(cmdCode2); + } + lastA = flagA; + lastB = flagB; + bool flagSw = !digitalRead(pinSw); + if (flagSw == lastSw) return; + if (flagSw) { + switch (devNum) { + case 1: + XP.commandTrigger(cmdCode3); + break; + case 2: + alt1000Mode = !alt1000Mode; + break; + case 3: + baroMode = !baroMode; + break; + } + } + lastSw = flagSw; +} + +void checkStatus(int pin, bool& last, int cmdCode) { + bool flag = !digitalRead(pin); + if(flag == last) return; + if(flag) XP.commandTrigger(cmdCode); + last = flag; +} + +void xplInboundHandler(inStruct *inData) { + +lcd.setCursor(0,0); + + if (inData->handle == beacon) { + lcd.print("Beacon: "); + if (inData->inLong) lcd.print("ON "); //digitalWrite(beaconLed,HIGH); + else lcd.print("OFF"); //digitalWrite(beaconLed,LOW); + } else if (inData->handle == landing) { + lcd.print("Landing: "); + + if (inData->inLong) lcd.print("ON "); // digitalWrite(landingLed,HIGH); + else lcd.print("OFF"); // digitalWrite(landingLed,LOW); + } else if (inData->handle == taxi) { + lcd.print("Taxi: "); + if (inData->inLong) lcd.print("ON "); //digitalWrite(taxiLed,HIGH); + else lcd.print("OFF"); //digitalWrite(taxiLed,LOW); + } else if (inData->handle == navLights) { + lcd.print("Nav: "); + if (inData->inLong) lcd.print("ON "); //digitalWrite(navLightsLed,HIGH); + else lcd.print("OFF"); //digitalWrite(navLightsLed,LOW); + } else if (inData->handle == strobes) { + lcd.print("Strobes: "); + if (inData->inLong) lcd.print("ON "); //digitalWrite(strobesLed,HIGH); + else lcd.print("OFF"); //digitalWrite(strobesLed,LOW); + } +} + +void xplRegister() +{ +beacon = XP.registerDataRef(F("LTbcn") ); + XP.requestUpdates(beacon, 100, 0); + taxi = XP.registerDataRef(F("LTtax") ); + XP.requestUpdates(taxi, 100, 0); + landing = XP.registerDataRef(F("LTlnd") ); + XP.requestUpdates(landing, 100, 0); + navLights = XP.registerDataRef(F("LTnav") ); + XP.requestUpdates(navLights, 100, 0); + strobes = XP.registerDataRef(F("LTstr") ); + XP.requestUpdates(strobes, 100, 0); + + cmdBcnToggle = XP.registerCommand(F("sim/lights/beacon_lights_toggle")); + cmdLandToggle = XP.registerCommand(F("sim/lights/landing_lights_toggle")); + cmdNavToggle = XP.registerCommand(F("sim/lights/nav_lights_toggle")); + cmdTaxiToggle = XP.registerCommand(F("sim/lights/taxi_lights_toggle")); + cmdStrobeToggle = XP.registerCommand(F("sim/lights/strobe_lights_toggle")); + cmdBattToggle = XP.registerCommand(F("sim/electrical/batteries_toggle")); + cmdAvioToggle = XP.registerCommand(F("sim/systems/avionics_toggle")); + cmdAltUp = XP.registerCommand(F("sim/autopilot/altitude_up")); + cmdAltDown = XP.registerCommand(F("sim/autopilot/altitude_down")); + cmdHeadUp = XP.registerCommand(F("sim/autopilot/heading_up")); + cmdHeadDown = XP.registerCommand(F("sim/autopilot/heading_down")); + cmdBaroUp = XP.registerCommand(F("sim/instruments/barometer_up")); + cmdBaroDown = XP.registerCommand(F("sim/instruments/barometer_down")); + cmdHeadSync = XP.registerCommand(F("sim/GPS/g1000n1_hdg_sync")); +// cmdHeadSync = XP.registerCommand(F("sim/autopilot/heading_sync")); + cmdAlt100_Up = XP.registerCommand(F("sim/GPS/g1000n1_alt_inner_up")); + cmdAlt100_Down = XP.registerCommand(F("sim/GPS/g1000n1_alt_inner_down")); + cmdAlt1000_Up = XP.registerCommand(F("sim/GPS/g1000n1_alt_outer_up")); + cmdAlt1000_Down = XP.registerCommand(F("sim/GPS/g1000n1_alt_outer_down")); + cmdGenToggle = XP.registerCommand(F("sim/electrical/generators_toggle")); + cmdCrsUp = XP.registerCommand(F("sim/GPS/g1000n1_crs_up")); + cmdCrsDown = XP.registerCommand(F("sim/GPS/g1000n1_crs_down")); +} + +void xplShutdown() +{ + // if you need to do things when xplane shuts down or unloads an aircraft, do it here. + +} + +void ErrorBlink(int pin, int count) +{ + for (int i = 0; i< count; i++) + { + digitalWrite(pin, HIGH); + delay(200); + digitalWrite(pin, LOW); + delay(100); + } +} diff --git a/XPLPro_Arduino/XPLPro/examples/XPLProBeaconDemo/XPLProBeaconDemo.ino b/XPLPro_Arduino/XPLPro/examples/XPLProBeaconDemo/XPLProBeaconDemo.ino new file mode 100644 index 0000000..553b0dc --- /dev/null +++ b/XPLPro_Arduino/XPLPro/examples/XPLProBeaconDemo/XPLProBeaconDemo.ino @@ -0,0 +1,111 @@ + + +/* + * + * XPLProBeaconDemo + * + * Created by Curiosity Workshop for XPL/Pro arduino->XPlane system. + * + * This sketch was developed and tested on an Arduino Mega. + * + To report problems, download updates and examples, suggest enhancements or get technical support: + + discord: https://discord.gg/RacvaRFsMW + patreon: www.patreon.com/curiosityworkshop + YouTube: https://youtube.com/channel/UCISdHdJIundC-OSVAEPzQIQ + * + * + */ + +#include +#include // include file for the X-plane direct interface +XPLPro XP(&Serial); // create an instance of it + + +long int startTime; + +int drefBeacon; // this stores a handle to the beacon light dataref + +void setup() +{ + + pinMode(LED_BUILTIN, OUTPUT); // built in LED on arduino board will turn on and off with the status of the beacon light + + Serial.begin(XPL_BAUDRATE); // start serial interface. Baudrate is specified in the header, dont change + + /* + needed for initialization. Parameters are: + a texual identifier of your device + your function that will be called when xplane and the plugin are ready for dataref and command registrations + your function that will be called when xplane either shuts down or unloads an aircraft model + your function that will be called when we have requested sends of datarefs that have changed + */ + XP.begin("XPLPro Beacon Light Demo!", &xplRegister, &xplShutdown, &xplInboundHandler); + digitalWrite(LED_BUILTIN, LOW); + + +} + + +void loop() +{ + + XP.xloop(); // needs to run every cycle. + +/************************************************************************************************************************************ + * everything after the next line will only occur every 100ms. You can also utilize other time values. + * This helps maintain serial data flow and also helps with switch debounce. + * do NOT add delays anywhere in the loop cycle, it will interfere with the reception of serial data from xplane and the plugin. + ************************************************************************************************************************************ +*/ + + if (millis() - startTime > 100) startTime = millis(); else return; + +} + +/* + * This function is the callback function we specified that will be called any time our requested data is sent to us. + * handle is the handle to the dataref. The following variables within the plugin are how we receive the data: + * + * inStruct *inData is a pointer to a structure that contains information about the incoming dataref. + * + * int inData->handle The handle of the incoming dataref + * int inData->element If the dataref is an array style dataref, this is the element of the array + * long inData->inLong long value for datarefs that are long values + * float inData->inFloat float value for datarefs that are float values + */ + void xplInboundHandler(inStruct *inData) +{ + if (inData->handle == drefBeacon) + { if (inData->inLong) digitalWrite(LED_BUILTIN, HIGH); // if beacon is on set the builtin led on + else digitalWrite(LED_BUILTIN, LOW); + } + + +} + +/* + * this is the function we set as a callback for when the plugin is ready to receive dataref and command bindings requests + * It could be called multiple times if for instance xplane is restarted or loads a different aircraft + */ +void xplRegister() +{ +/* + * This example registers a dataref for the beacon light. + * In the inbound handler section of the code we will turn on/off the LED on the arduino board to represent the status of the beacon light within xplane. + * On non-AVR boards remove the F() macro. + * + */ + drefBeacon = XP.registerDataRef(F("sim/cockpit2/switches/beacon_on") ); + XP.requestUpdates(drefBeacon, 100, 0); // Tell xplane to send us updates when the status of the beacon light changes. + // 100 means don't update more often than every 100ms and 0 is a precision specifier for float variables which is explained in another example, use 0 for now. + + + +} + +void xplShutdown() +{ + // if you need to do things when xplane shuts down or unloads an aircraft, do it here. + +} diff --git a/XPLPro_Arduino/XPLPro/examples/XPLProMax72XXExample/XPLProMax72XXExample.ino b/XPLPro_Arduino/XPLPro/examples/XPLProMax72XXExample/XPLProMax72XXExample.ino new file mode 100644 index 0000000..427b35e --- /dev/null +++ b/XPLPro_Arduino/XPLPro/examples/XPLProMax72XXExample/XPLProMax72XXExample.ino @@ -0,0 +1,85 @@ + +/* + * + * XPLProMax72XXExample + * + * Created by Curiosity Workshop for XPL/Pro arduino->XPlane system. + * + * This sketch was developed and tested on an Arduino Mega. + * + To report problems, download updates and examples, suggest enhancements or get technical support: + + discord: https://discord.gg/RacvaRFsMW + patreon: www.patreon.com/curiosityworkshop + YouTube: https://youtube.com/channel/UCISdHdJIundC-OSVAEPzQIQ + * + * + */ + +#include +#include // for MAX72xx displays. This is an external library that you need to install. +#include + +XPLPro XP(&Serial); +LedControl myLedDisplays=LedControl(34,36,35,1); // data, clock, cs, number of devices, they can be chained. + +int drefAltitude; // handle to current altitude dataref + +void setup() +{ + Serial.begin(XPL_BAUDRATE); + XP.begin("XPLPro MAX72XX Display Example", &xplRegister, &xplShutdown, &xplInboundHandler); + + myLedDisplays.shutdown(0, false); myLedDisplays.setIntensity(0, 5); // start the LED displays + +} + +void loop() +{ + XP.xloop(); + + //if (millis() % 1000 > 900) digitalWrite(LED_BUILTIN, HIGH); else digitalWrite(LED_BUILTIN, LOW); // Heartbeat +} + +void xplInboundHandler(inStruct *inData) +{ + + if (inData->handle == drefAltitude) { printNumber(0, "% 5.3u", inData->inFloat, 1, &myLedDisplays); return; } + +} + +void xplShutdown() +{ + + myLedDisplays.shutdown(0, true); +} + + +void xplRegister() +{ + + drefAltitude = XP.registerDataRef(F("sim/cockpit2/gauges/indicators/altitude_ft_pilot")); + XP.requestUpdates(drefAltitude, 100, 10); + //XP.registerDataRef(F("sim/cockpit2/switches/strobe_lights_on")) ); + + +} + + + +/* + * prints a number on the MAX 72xx display + */ +void printNumber(int ledDisplay, char *printMask, long int v, int pos, LedControl *lc) +{ +char tString[10]; +int tpos = strlen(tString) + pos; + + sprintf(tString, printMask, v); + for (int i = strlen(tString)-1; i>=0; i--) + { + lc->setChar(ledDisplay, tpos++, tString[i], false); + } + + +} diff --git a/XPLPro_Demo/XPLProMultiDemo.ino b/XPLPro_Arduino/XPLPro/examples/XPLProMultiDemo/XPLProMultiDemo.ino similarity index 92% rename from XPLPro_Demo/XPLProMultiDemo.ino rename to XPLPro_Arduino/XPLPro/examples/XPLProMultiDemo/XPLProMultiDemo.ino index 934be5a..3b54908 100644 --- a/XPLPro_Demo/XPLProMultiDemo.ino +++ b/XPLPro_Arduino/XPLPro/examples/XPLProMultiDemo/XPLProMultiDemo.ino @@ -1,278 +1,281 @@ - - -/* - * - * XPLProMultiDemo - * - * Created by Curiosity Workshop for XPL/Pro arduino->XPlane system. - * - * This sketch was developed and tested on an Arduino Mega. - * - To report problems, download updates and examples, suggest enhancements or get technical support: - - discord: https://discord.gg/RacvaRFsMW - patreon: www.patreon.com/curiosityworkshop - YouTube: https://youtube.com/channel/UCISdHdJIundC-OSVAEPzQIQ - * - * - */ - -#include -#include - -#include // include file for the X-plane direct interface -XPLPro XP(&Serial); // create an instance of it - -LiquidCrystal_I2C lcd(0x26,16,2); -long int startTime; - - -#define PIN_GOAROUND 22 // go around button -#define PIN_GEARTOGGLE 23 // pin for gear toggle - -#define PIN_PAUSE 9 // pin to pause xplane -#define PIN_NAVLIGHT 24 // pin for nav light switch -#define PIN_LANDINGLIGHT 7 // pin for landing light switch -#define PIN_SAYSOMETHING 10 // for demonstration of speech function -#define PIN_THROTTLE1 A0 // throttle 1 -#define PIN_THROTTLE2 A1 // throttle 2 - -#define PIN_LEFTGEARLED 40 // for nose gear LED -#define PIN_NOSEGEARLED 41 // left gear LED -#define PIN_RIGHTGEARLED 42 // right gear LED - - -int drefBeacon; -int drefNavLight, navlightPrevious = -1; -int drefLdgLight; -int drefTaxiLight; -int drefGearDeployed; -int drefThrottle; float throttle1Previous; float throttle2Previous; -int drefEngineRPM; - - -int cmdGearToggle; // a handle for toggling landing gear up and down -int cmdPause; // pause the sim -int cmdToga; // take off/go around - - -void setup() -{ - lcd.init(); - lcd.backlight(); - lcd.setCursor(0,0); - lcd.print("XPLPro Demo!"); - - pinMode(PIN_GEARTOGGLE, INPUT_PULLUP); // if you are doing pin handling yourself you will want a pullup resistor or use the built-in one - pinMode(PIN_NAVLIGHT, INPUT_PULLUP); // otherwise the value will be erratic when the pin is open and nobody likes that. - pinMode(PIN_GOAROUND, INPUT_PULLUP); - pinMode(PIN_LANDINGLIGHT, INPUT_PULLUP); - pinMode(PIN_SAYSOMETHING, INPUT_PULLUP); - pinMode(PIN_PAUSE, INPUT_PULLUP); - - pinMode(LED_BUILTIN, OUTPUT); // built in LED on arduino board for debug and demonstration purposes - pinMode(PIN_LEFTGEARLED, OUTPUT); - pinMode(PIN_NOSEGEARLED, OUTPUT); - pinMode(PIN_RIGHTGEARLED, OUTPUT); - - Serial.begin(XPL_BAUDRATE); // start serial interface. Baudrate is specified in the header, dont change - - /* - needed for initialization. Parameters are: - a texual identifier of your device - your function that will be called when xplane and the plugin are ready for dataref and command registrations - your function that will be called when xplane either shuts down or unloads an aircraft model - your function that will be called when we have requested sends of datarefs that have changed - */ - XP.begin("XPLCore Multi Demo!", ®isterXplaneStuff, &shutdownXplaneStuff, &inboundHandler); - digitalWrite(LED_BUILTIN, LOW); - - -} - - -void loop() -{ - - - - XP.xloop(); // needs to run every cycle. - -/************************************************************************************************************************************ - * everything after the next line will only occur every 100ms. You can also utilize other time values. - * This helps maintain serial data flow and also helps with switch debounce. - * do NOT add delays anywhere in the loop cycle, it will interfere with the reception of serial data from xplane and the plugin. - ************************************************************************************************************************************ -*/ - - if (millis() - startTime > 100) startTime = millis(); else return; - - -/* - * This reads the status of the assigned pins and triggers commands accordingly. It would be best to use a button library for this for debounce and one-shot purposes - * I am not using one for simplicity in the demo. - */ - if (!digitalRead(PIN_GEARTOGGLE)) XP.commandTrigger(cmdGearToggle); - if (!digitalRead(PIN_GOAROUND)) XP.commandTrigger(cmdToga); - if (!digitalRead(PIN_PAUSE)) XP.commandTrigger(cmdPause); - - - if (digitalRead(PIN_NAVLIGHT) != navlightPrevious) // to conserve the flow of data we should keep track of the previously sent value so we don't send a new one every cycle - { - navlightPrevious = digitalRead(PIN_NAVLIGHT); - XP.datarefWrite(drefNavLight, navlightPrevious); - } - - //landingLights = digitalRead(PIN_LANDINGLIGHT); - - - - -/* - * This reads the status of the assigned pin and sends a message to initiation speech. This should probably use a switch library for one-shot so it - * doesnt repeat send/stutter while it is being held down. For now it works for demo purposes. - */ - if (!digitalRead(PIN_SAYSOMETHING)) XP.sendSpeakMessage("speech demonstration"); - -/* - * Read analog position of potentiometers representing throttles. Use the mapfloat function (below) to change the read value 0-1024 to a float 0.0 - 1.0 - * In this case the throttle dataref is an array, so we specify which element of the array as the third parameter of datarefWrite. - * We also should track and compare to the previous value so that we don't send the same value every cycle. - */ - int throttle1Current = analogRead(PIN_THROTTLE1) /10; // I am dividing by 10 here because I don't need 1024 units of resolution for the throttle position and this will reduce dataflow. - if (throttle1Current != throttle1Previous) - { - throttle1Previous = throttle1Current; - XP.datarefWrite(drefThrottle, throttle1Current, 0); // we already requested scaling (map) from the plugin so just send the raw data. - } - - int throttle2Current = analogRead(PIN_THROTTLE2) /10; - if (throttle2Current != throttle2Previous) - { - throttle2Previous = throttle2Current; - XP.datarefWrite(drefThrottle, throttle2Current, 1); - } - - - -} - -/* - * This function is the callback function we specified that will be called any time our requested data is sent to us. - * handle is the handle to the dataref. The following variables within the plugin are how we receive the data: - * - * readValueLong If the dataref is of type INT - * readValueFloat If the dataref is of type FLOAT - * readValueElement If the dataref is an array, this is the element that changed - */ -void inboundHandler(inStruct *inData) -{ - if (inData->handle == drefBeacon) - { if (inData->inLong) digitalWrite(LED_BUILTIN, HIGH); // if beacon is on set the builtin led on - else digitalWrite(LED_BUILTIN, LOW); - } - - if (inData->handle == drefEngineRPM) // display RPM on the LCD - { lcd.setCursor(0,1); - lcd.print("Alt: "); - lcd.print((int)inData->inFloat); // casted to INT to remove decimals - } - -/* - * This reads the status of the landing gear. You could turn on lights as in this example. The position is represented as a float between 0 and 1, 1 representing down and locked. - */ - if (inData->handle == drefGearDeployed) - { switch (inData->element ) - { - case 0: // nose gear - if (inData->inFloat == 1) digitalWrite(PIN_NOSEGEARLED, HIGH); else digitalWrite(PIN_NOSEGEARLED, LOW); - break; - - case 1: // Left Main - if (inData->inFloat == 1) digitalWrite(PIN_LEFTGEARLED, HIGH); else digitalWrite(PIN_LEFTGEARLED, LOW); - break; - - case 2: // Right Main - if (inData->inFloat == 1) digitalWrite(PIN_RIGHTGEARLED, HIGH); else digitalWrite(PIN_RIGHTGEARLED, LOW); - break; - - } - } - - - -} - -void registerXplaneStuff() // this is the function we set as a callback for when the plugin is ready to receive dataref and command bindings requests -{ - - - -/* - * This example registers a dataref for the beacon light. - * In the loop section of the code we will turn on/off the LED on the arduino board to represent the status of the beacon light within xplane. - * On non-AVR boards remove the F() macro. - * - */ - drefBeacon = XP.registerDataRef(F("sim/cockpit2/switches/beacon_on") ); - XP.requestUpdates(drefBeacon, 100, 0); // Tell xplane to send us updates when the status of the beacon light changes. - // 100 means don't update more often than every 100ms and 0 is a resolution divider which is explained in another dataref, use 0 if no divider required - - -/* - * This example registers a dataref for the nav light. This time we will control the status of the light with a switch. - * It is up to you to confirm that the datarefs you utilize are writable. A handy website allows you to search - * for them and understand their attributes: https://developer.x-plane.com/datarefs/ - * - * In the loop section of the code we will check the status of the switch send it to the navLight dataref within Xplane. - * To test this, connect one side of a normal toggle switch to ground and the other to the pin used in the #define for PIN_NAVLIGHT (9) - */ - drefNavLight = XP.registerDataRef(F("sim/cockpit/electrical/nav_lights_on") ); - - -/* - * The text for the names of datarefs and commands can be a large memory hit for many arduino boards. Here are some ways to reduce the impact: - * - * This first one utilizes abbreviations. In the folder where the XPLDirect plugin is installed there is a file called abbreviations.txt. You can add abbreviations to this as you like. - * The plugin will search for the abbreviation string you use for dataref names and command names, then convert them to the full length specified. Example: - * - * LTland = sim/cockpit/electrical/landing_lights_on - * - * This comes preset in the distrubution version of the abbreviations.txt file so we will try it in the example: - */ - drefLdgLight = XP.registerDataRef(F("LTland") ); // "LTland" will be converted to "sim/cockpit/electrical/landing_lights_on" - drefTaxiLight = XP.registerDataRef(F("LTtaxi")); - - -/* - * more examples for the testing box - */ - drefGearDeployed = XP.registerDataRef(F("sim/flightmodel2/gear/deploy_ratio") ); // this will be updated from xplane to tell us what position the landing gear is in - XP.requestUpdates(drefGearDeployed, 100, 1, 0); // Tell xplane to send us updates when the status of the gear position changes. - XP.requestUpdates(drefGearDeployed, 100, 1, 1); // 100 means don't update more often than every 100ms and .1 is a resolution divider to reduce data flow. eg we probably arent interested in .001 of gear position. - XP.requestUpdates(drefGearDeployed, 100, 1, 2); // The additional parameter is the array element to reference, since this dataref is an array of values. 0=nose, 1=left, 2=right - - drefThrottle = XP.registerDataRef(F("sim/cockpit2/engine/actuators/throttle_ratio") ); // This is an array dataref. We will be sending this data from a potentiometer - XP.setScaling(drefThrottle, 0, 102, 0, 1); // this uses a map style function to convert values 0-102 to a float value of 0-1. Since analogRead returns 0-1024, we will divide it - // by 10 when we read it then convert 0-102 to a float value of 0-1. - - drefEngineRPM = XP.registerDataRef(F("sim/cockpit2/gauges/indicators/altitude_ft_pilot") ); // indicated altitude for display on the LCD screen. This is a float - XP.requestUpdates(drefEngineRPM, 100, 10); // divide by 10 to show increments of 10 feet - - -/* - * Now register commands. - * - */ - cmdPause = XP.registerCommand(F("sim/operation/pause_toggle") ); - cmdToga = XP.registerCommand(F("sim/autopilot/take_off_go_around") ); - cmdGearToggle = XP.registerCommand(F("sim/flight_controls/landing_gear_toggle") ); - - -} - -void shutdownXplaneStuff() -{ - // if you need to do things when xplane shuts down or unloads an aircraft, do it here. - -} + + +/* + * + * XPLProMultiDemo + * + * Created by Curiosity Workshop for XPL/Pro arduino->XPlane system. + * + * This sketch was developed and tested on an Arduino Mega. + * + To report problems, download updates and examples, suggest enhancements or get technical support: + + discord: https://discord.gg/RacvaRFsMW + patreon: www.patreon.com/curiosityworkshop + YouTube: https://youtube.com/channel/UCISdHdJIundC-OSVAEPzQIQ + * + * + */ + +#include +#include + +#include // include file for the X-plane direct interface +XPLPro XP(&Serial); // create an instance of it + +LiquidCrystal_I2C lcd(0x26,16,2); + + +long int startTime; + + +#define PIN_GOAROUND 22 // go around button +#define PIN_GEARTOGGLE 23 // pin for gear toggle + +#define PIN_PAUSE 9 // pin to pause xplane +#define PIN_NAVLIGHT 24 // pin for nav light switch +#define PIN_LANDINGLIGHT 7 // pin for landing light switch +#define PIN_SAYSOMETHING 10 // for demonstration of speech function +#define PIN_THROTTLE1 A0 // throttle 1 +#define PIN_THROTTLE2 A1 // throttle 2 + +#define PIN_LEFTGEARLED 40 // for nose gear LED +#define PIN_NOSEGEARLED 41 // left gear LED +#define PIN_RIGHTGEARLED 42 // right gear LED + + +int drefBeacon; +int drefNavLight, navlightPrevious = -1; +int drefLdgLight; +int drefTaxiLight; +int drefGearDeployed; +int drefThrottle; float throttle1Previous; float throttle2Previous; +int drefEngineRPM; + + +int cmdGearToggle; // a handle for toggling landing gear up and down +int cmdPause; // pause the sim +int cmdToga; // take off/go around + + +void setup() +{ + lcd.init(); + lcd.backlight(); + lcd.setCursor(0,0); + lcd.print("XPLPro Demo!"); + + pinMode(PIN_GEARTOGGLE, INPUT_PULLUP); // if you are doing pin handling yourself you will want a pullup resistor or use the built-in one + pinMode(PIN_NAVLIGHT, INPUT_PULLUP); // otherwise the value will be erratic when the pin is open and nobody likes that. + pinMode(PIN_GOAROUND, INPUT_PULLUP); + pinMode(PIN_LANDINGLIGHT, INPUT_PULLUP); + pinMode(PIN_SAYSOMETHING, INPUT_PULLUP); + pinMode(PIN_PAUSE, INPUT_PULLUP); + + pinMode(LED_BUILTIN, OUTPUT); // built in LED on arduino board for debug and demonstration purposes + pinMode(PIN_LEFTGEARLED, OUTPUT); + pinMode(PIN_NOSEGEARLED, OUTPUT); + pinMode(PIN_RIGHTGEARLED, OUTPUT); + + Serial.begin(XPL_BAUDRATE); // start serial interface. Baudrate is specified in the header, dont change + + /* + needed for initialization. Parameters are: + a texual identifier of your device + your function that will be called when xplane and the plugin are ready for dataref and command registrations + your function that will be called when xplane either shuts down or unloads an aircraft model + your function that will be called when we have requested sends of datarefs that have changed + */ + XP.begin("XPLPro Multi Demo!", &xplRegister, &xplShutdown, &xplInboundHandler); + digitalWrite(LED_BUILTIN, LOW); + + +} + + +void loop() +{ + + + + XP.xloop(); // needs to run every cycle. + +/************************************************************************************************************************************ + * everything after the next line will only occur every 100ms. You can also utilize other time values. + * This helps maintain serial data flow and also helps with switch debounce. + * do NOT add delays anywhere in the loop cycle, it will interfere with the reception of serial data from xplane and the plugin. + ************************************************************************************************************************************ +*/ + + if (millis() - startTime > 100) startTime = millis(); else return; + + +/* + * This reads the status of the assigned pins and triggers commands accordingly. It would be best to use a button library for this for debounce and one-shot purposes + * I am not using one for simplicity in the demo. + */ + if (!digitalRead(PIN_GEARTOGGLE)) XP.commandTrigger(cmdGearToggle); + if (!digitalRead(PIN_GOAROUND)) XP.commandTrigger(cmdToga); + if (!digitalRead(PIN_PAUSE)) XP.commandTrigger(cmdPause); + + + if (digitalRead(PIN_NAVLIGHT) != navlightPrevious) // to conserve the flow of data we should keep track of the previously sent value so we don't send a new one every cycle + { + navlightPrevious = digitalRead(PIN_NAVLIGHT); + XP.datarefWrite(drefNavLight, navlightPrevious); + } + + //landingLights = digitalRead(PIN_LANDINGLIGHT); + + + + +/* + * This reads the status of the assigned pin and sends a message to initiation speech. This should probably use a switch library for one-shot so it + * doesnt repeat send/stutter while it is being held down. For now it works for demo purposes. + */ + if (!digitalRead(PIN_SAYSOMETHING)) XP.sendSpeakMessage("speech demonstration"); + +/* + * Read analog position of potentiometers representing throttles. Use the mapfloat function (below) to change the read value 0-1024 to a float 0.0 - 1.0 + * In this case the throttle dataref is an array, so we specify which element of the array as the third parameter of datarefWrite. + * We also should track and compare to the previous value so that we don't send the same value every cycle. + */ + int throttle1Current = analogRead(PIN_THROTTLE1) /10; // I am dividing by 10 here because I don't need 1024 units of resolution for the throttle position and this will reduce dataflow. + if (throttle1Current != throttle1Previous) + { + throttle1Previous = throttle1Current; + XP.datarefWrite(drefThrottle, throttle1Current, 0); // we already requested scaling (map) from the plugin so just send the raw data. + } + + int throttle2Current = analogRead(PIN_THROTTLE2) /10; + if (throttle2Current != throttle2Previous) + { + throttle2Previous = throttle2Current; + XP.datarefWrite(drefThrottle, throttle2Current, 1); + } + + + +} + +/* + * This function is the callback function we specified that will be called any time our requested data is sent to us. + * handle is the handle to the dataref. The following values are transfered to the callback through inStruct: + * + * int inData->handle The handle of the incoming dataref + * int inData->element If the dataref is an array style dataref, this is the element of the array + * long inData->inLong long value for datarefs that are long values + * float inData->inFloat float value for datarefs that are float values + */ +void xplInboundHandler(inStruct *inData) +{ + if (inData->handle == drefBeacon) + { if (inData->inLong) digitalWrite(LED_BUILTIN, HIGH); // if beacon is on set the builtin led on + else digitalWrite(LED_BUILTIN, LOW); + } + + if (inData->handle == drefEngineRPM) // display RPM on the LCD + { lcd.setCursor(0,1); + lcd.print("Alt: "); + lcd.print((int)inData->inFloat); // casted to INT to remove decimals + } + +/* + * This reads the status of the landing gear. You could turn on lights as in this example. The position is represented as a float between 0 and 1, 1 representing down and locked. + */ + if (inData->handle == drefGearDeployed) + { switch (inData->element ) + { + case 0: // nose gear + if (inData->inFloat == 1) digitalWrite(PIN_NOSEGEARLED, HIGH); else digitalWrite(PIN_NOSEGEARLED, LOW); + break; + + case 1: // Left Main + if (inData->inFloat == 1) digitalWrite(PIN_LEFTGEARLED, HIGH); else digitalWrite(PIN_LEFTGEARLED, LOW); + break; + + case 2: // Right Main + if (inData->inFloat == 1) digitalWrite(PIN_RIGHTGEARLED, HIGH); else digitalWrite(PIN_RIGHTGEARLED, LOW); + break; + + } + } + + + +} + +void xplRegister() // this is the function we set as a callback for when the plugin is ready to receive dataref and command bindings requests +{ + + + +/* + * This example registers a dataref for the beacon light. + * In the loop section of the code we will turn on/off the LED on the arduino board to represent the status of the beacon light within xplane. + * On non-AVR boards remove the F() macro. + * + */ + drefBeacon = XP.registerDataRef(F("sim/cockpit2/switches/beacon_on") ); + XP.requestUpdates(drefBeacon, 100, 0); // Tell xplane to send us updates when the status of the beacon light changes. + // 100 means don't update more often than every 100ms and 0 is a resolution divider which is explained in another dataref, use 0 if no divider required + + +/* + * This example registers a dataref for the nav light. This time we will control the status of the light with a switch. + * It is up to you to confirm that the datarefs you utilize are writable. A handy website allows you to search + * for them and understand their attributes: https://developer.x-plane.com/datarefs/ + * + * In the loop section of the code we will check the status of the switch send it to the navLight dataref within Xplane. + * To test this, connect one side of a normal toggle switch to ground and the other to the pin used in the #define for PIN_NAVLIGHT (9) + */ + drefNavLight = XP.registerDataRef(F("sim/cockpit/electrical/nav_lights_on") ); + + +/* + * The text for the names of datarefs and commands can be a large memory hit for many arduino boards. Here are some ways to reduce the impact: + * + * This first one utilizes abbreviations. In the folder where the XPLDirect plugin is installed there is a file called abbreviations.txt. You can add abbreviations to this as you like. + * The plugin will search for the abbreviation string you use for dataref names and command names, then convert them to the full length specified. Example: + * + * LTland = sim/cockpit/electrical/landing_lights_on + * + * This comes preset in the distrubution version of the abbreviations.txt file so we will try it in the example: + */ + drefLdgLight = XP.registerDataRef(F("LTland") ); // "LTland" will be converted to "sim/cockpit/electrical/landing_lights_on" + drefTaxiLight = XP.registerDataRef(F("LTtaxi")); + + +/* + * more examples for the testing box + */ + drefGearDeployed = XP.registerDataRef(F("sim/flightmodel2/gear/deploy_ratio") ); // this will be updated from xplane to tell us what position the landing gear is in + XP.requestUpdates(drefGearDeployed, 100, 1, 0); // Tell xplane to send us updates when the status of the gear position changes. + XP.requestUpdates(drefGearDeployed, 100, 1, 1); // 100 means don't update more often than every 100ms and .1 is a resolution divider to reduce data flow. eg we probably arent interested in .001 of gear position. + XP.requestUpdates(drefGearDeployed, 100, 1, 2); // The additional parameter is the array element to reference, since this dataref is an array of values. 0=nose, 1=left, 2=right + + drefThrottle = XP.registerDataRef(F("sim/cockpit2/engine/actuators/throttle_ratio") ); // This is an array dataref. We will be sending this data from a potentiometer + XP.setScaling(drefThrottle, 0, 102, 0, 1); // this uses a map style function to convert values 0-102 to a float value of 0-1. Since analogRead returns 0-1024, we will divide it + // by 10 when we read it then convert 0-102 to a float value of 0-1. + + drefEngineRPM = XP.registerDataRef(F("sim/cockpit2/gauges/indicators/altitude_ft_pilot") ); // indicated altitude for display on the LCD screen. This is a float + XP.requestUpdates(drefEngineRPM, 100, 10); // divide by 10 to show increments of 10 feet + + +/* + * Now register commands. + * + */ + cmdPause = XP.registerCommand(F("sim/operation/pause_toggle") ); + cmdToga = XP.registerCommand(F("sim/autopilot/take_off_go_around") ); + cmdGearToggle = XP.registerCommand(F("sim/flight_controls/landing_gear_toggle") ); + + +} + +void xplShutdown() +{ + // if you need to do things when xplane shuts down or unloads an aircraft, do it here. + +} diff --git a/XPLPro_Arduino/XPLPro/examples/XPLProMultiplexerExample/Multiplexer Wiring Diagram.jpg b/XPLPro_Arduino/XPLPro/examples/XPLProMultiplexerExample/Multiplexer Wiring Diagram.jpg new file mode 100644 index 0000000000000000000000000000000000000000..d48a3e4c1e73fad5c40d61d509586e81336d2a7f GIT binary patch literal 488195 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

1j8Ck2bU7aYJ8)x`DpWTa(CC=>&#SmHlE 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