SDK Question Odd Behavior With oapiOpenInputBox

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
Hi all,

In an MFD I'm working on, I'm trying to allow the user to input a target base via oapiOpenInputBox, though I'm getting some strange behavior.

The goal in this simple case is to simply open a dialog box, have the user input a string, and then print the string to the MFD. I have the following code (I'm only showing relevant code here, not the full file contents):

MFDTemplate.cpp:
Code:
#define STRICT
#define ORBITER_MODULE
#include "windows.h"
#include "orbitersdk.h"
#include "MFDTemplate.h"

// Global variables
int g_MFDmode; // identifier for new MFD mode
char* testStr;
char* placeholder;

bool MFDTemplate::ConsumeButton(int bt, int event) {

	bool UpdateGlobalVariableTestFxn(void *id, char *str, void *user_data);

	// Do nothing for click/hold
	if (!(event &PANEL_MOUSE_LBDOWN))
	{
		return false;
	}

	if (bt == 0) {
		placeholder = testStr;
		oapiOpenInputBox("Test", UpdateGlobalVariableTestFxn, 0, 20, (void*)this);
		return true;
	}

	return false;
}

bool UpdateGlobalVariableTestFxn(void *id, char *str, void *user_data) {
	testStr= str;
	return true;
}

bool MFDTemplate::Update (oapi::Sketchpad *skp)
{
	Title (skp, "MFD Template");

	skp->SetFont (font);
	skp->SetTextAlign (oapi::Sketchpad::CENTER, oapi::Sketchpad::BASELINE);
	skp->SetTextColor (0x00FFFF);
	skp->Text (W/2, H/2, testStr, 12);

	return true;
}

I would like the old string to be displayed on the MFD until the user types the new string and hits enter. I'm getting some bizarre behavior though:
1. Everything works normally the first time (presumably because testStr is initialized to NULL and there's nothing to display).
2. The second time and onward, whenever the button is pressed, testStr is set to "" when the line oapiOpenInputBox(... is executed. I tried to get around this using string placeholder, but placeholder is also set to "" when the oapiOpenInputBox line is called! This makes no sense, since placeholder is only assigned a value in one line of code.

Any help would be greatly appreciated.
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Try this:

char testStr[65];

and in UpdateGlobalVariableTestFxn

strncpy_s(testStr, 64, str);



I.e. you need to pull the string into a piece of permanent space, not just copy the pointer to a piece of dynamic heap that will get overwritten.

By the way - you need to understand the whole MFD destruction/creation model if you want to to anything more permanent with this testStr. Your whole MFD gets destroyed on any F8 keypress, any resize of your ExtMFD window, and any change of vessel. There's several techniques to address this - let me know if you need to know how to do this.
 

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
That'll do it, thanks! For those curious, I also got it to work with tempStr being a std::string.

I did learn the hard way that an MFD is destroyed and recreated with cockpit switches, etc. I'm making all of my main variables global in the sense that I'm initializing them in the .cpp file before all of the class function definitions, and it seems to be working. Was there anything else you were going to suggest doing?
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
yes - lots!

Generally, if you are declaring global variables, you are doing it wrong. Not exclusively, but there are better ways of doing it.

The simplest way to preserve state is SaveState and LoadState to config files, but that's a bit tedious. You'll often find people round here declaring a global core for their MFD, which persists across reinstantiations of the MFD. For several years, I have done a core for my MFDs to include a Global Core (invariant of vessel or MFD), a Vessel Core (preserving across vessel F3 selections) and a local core (vessel + MFD position). The code is a few dozen lines, and works every time. Happy to show you how to work it out.
 

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
Yes, that would be great. I assume it's something along the lines of a separate class which records each initiated instance of the MFD and saves parameters?
 

ADSWNJ

Scientist
Addon Developer
Joined
Aug 5, 2011
Messages
1,667
Reaction score
3
Points
38
Have a hunt through this: https://github.com/ADSWNJ/FlighttestRig

It's just a bit of play code, but the core is all there. Look at how GCore, VCOre and LCore are instantiated as persistent classes, that can survive the destruction of the whole MFD.
 

markl316

XR2 Ravenstar Commander
Addon Developer
Tutorial Publisher
Joined
Mar 30, 2008
Messages
450
Reaction score
1
Points
18
Hey, sorry I'm just answering this, I totally missed your reply haha. I traced through your code; my application only needs vessel-specific (not MFD-specific, so no need for a local core for me).

Works brilliantly, thanks! Just as an FYI for anybody else trying this: I was able to accomplish this with only two vessel classes: a global core, and a local core, without the intermediate MFDPersistent class.

Thanks for the help here!
 
Top