Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Loading an .ini file during runtime loads windows without docking. #6263

Closed
sarisman84 opened this issue Mar 22, 2023 · 4 comments
Closed

Loading an .ini file during runtime loads windows without docking. #6263

sarisman84 opened this issue Mar 22, 2023 · 4 comments
Labels
docking settings .ini persistance

Comments

@sarisman84
Copy link

sarisman84 commented Mar 22, 2023

Version: v1.89.2
Branch: docking

Back-ends: imgui_impl_win32.cpp + imgui_impl_dx11.cpp
Operating System: Windows 10

I am trying to load a .ini file during runtime in order to implement a editor ui layout system silimar to Unity's. Where the end user would be able to save and load the below IMGUI Window Layout

Skärmbild 2023-03-22 133612

Since each window element in my editor implementation is an instance of classes inheriting from a base Editor Class, i need to store each type of class in a separate .json file and create said instances in the same order they are saved. This however causes the .ini file to load incorrectly when calling the ImGui::LoadIniSettingsFromDisk() function:

Skärmbild 2023-03-22 133645

Here is the following implementation that i have concluded to thus far:

Loading Functions:

void ember::EmberGUI::LoadIniFile(const char* aFile)
{
	//Clears the previous init settings [Reduntant check]
	ImGui::ClearIniSettings();

	//Fetches the absolute path of the file and calls the ImGui::LoadIniSettingsFromDisk()
	std::filesystem::path dir(GetEditorDir().string() + aFile);
	std::cout << "Ini File Directory: " << dir.string() << "\n";
	ImGui::LoadIniSettingsFromDisk(dir.string().c_str());
}

std::filesystem::path ember::EmberGUI::GetEditorDir()
{
	//Constructs an absolute path the directoy that contains information about the Editor.
	std::string workingDir = std::filesystem::current_path().string();

	auto binPos = workingDir.find_last_of("\\bin");

	auto editorDir = std::string(workingDir.substr(0, binPos - 2));
	editorDir += "editor\\data\\";

	std::cout << "Editor Directory: " << editorDir << "\n";

	return std::filesystem::path(editorDir);
}

void ember::EmberGUI::LoadLayout(std::string aLayout, InitializeContext& someContext)
{
	//Read the json file
	ember::Json layoutData = ember::Json::Read(aLayout);

	//Check if the json file exists
	if (!layoutData) return;

	//Reduntant check to make sure that the io.InitFilename is indeed nullptr
	ImGuiIO& io = ImGui::GetIO();
	io.IniFilename = NULL;

	//Fetch the file address for the .ini file and the layout structure.
	auto imguiIni = layoutData.Get<std::string>("imguiData");
	auto layout = layoutData.Get<ember::Json>("layout");

	//Clear any previous editors that were alive beforehand.
	myRootContext->RemoveAllChildren();

	//Iterate through the layout and create an instance of each type stored.
	for (size_t i = 0; i < layout.GetArraySize(); i++)
	{
		auto data = layoutData.Get("layout", i);
		auto ins = CreateInstance(data.Get<StringID>("type"), someContext);
	}

	//Load the init file.
	LoadIniFile(imguiIni.c_str());
}

Saving Functions:

void ember::EmberGUI::SaveCurrentLayout(std::string aLayout, const bool aSetAsDefaultFlag)
{
	//Reduntant check to make sure that the io.InitFilename is indeed nullptr
	ImGuiIO& io = ImGui::GetIO();
	io.IniFilename = NULL;

	const char* layoutDir = GetLayoutDirectory();
	ember::Json layoutInfo;
	std::vector<ember::Json> data;

	//Get the current editors that are alive
	auto editorIns = myRootContext->GetEditorInstances();

	std::filesystem::path filePath(std::string(layoutDir) + "/" + aLayout);

	//Save the settings of the editors to the .ini file here
	ImGui::SaveIniSettingsToDisk((filePath.string() + ".ini").c_str());

	//Sort through the editors so that the very first editor made gets stored first.
	std::sort(editorIns.begin(), editorIns.end(), [this](ember::EmberEditorBase* aLhs, ember::EmberEditorBase* aRhs)
		{
			return aLhs->myID.id < aRhs->myID.id;
		});

	//Store the editors to the .json file.
	for (auto& editor : editorIns)
	{
		ember::Json editorInfo;

		editorInfo.Set("type", editor->myID.typeID);

		data.push_back(editorInfo);
	}


	layoutInfo.Set("layout", data);

	layoutInfo.Set("imguiData", std::string("layouts\\" + aLayout + ".ini"));

	std::string path(filePath.string() + ".json");

	ember::Json::Write(layoutInfo, path);

	ImGui::GetIO().WantSaveIniSettings = false;


	if (aSetAsDefaultFlag)
	{
		Json defaultData;

		defaultData.Set("defaultLayout", (filePath.string() + ".json"));

		ember::Json::Write(defaultData, std::string("../editor/data/defaultLayout.json"));
	}

}
@GamingMinds-DanielC
Copy link
Contributor

Version: Unknown (not latest) Branch: docking

That might be important and is very easy to find out. Version information is at the top of your imgui.h and imgui.cpp files.

In general, manual .ini file loading should happen between CreateContext() and the first call to NewFrame(). So to be safe, when you want to load a layout you should destroy the context, create a new one and then load the settings.

@ocornut ocornut added docking settings .ini persistance labels Mar 22, 2023
@ocornut
Copy link
Owner

ocornut commented Mar 22, 2023

In theory we support loading .ini files within the same context but e.g. #2573, #3215 seems to has issue whereas my test-bed did work (#2573 (comment)). Also maybe see e.g. #4033.
Loading should definitively be done BEFORE NewFrame() tho.

I'm unlikely to be able to provide support for that soon, docking has been tricky to deal with. I would say your best-bet is to narrow down simpler repro and test-beds based on examples and then experimenting with that.

@ocornut ocornut changed the title Loading an .ini file during runtime loads IMGUI windows without docking. Loading an .ini file during runtime loads windows without docking. Mar 22, 2023
@sarisman84
Copy link
Author

sarisman84 commented Mar 22, 2023

Sorry for the delay, i am currently busy with work.

When loading a new .ini file. Will any existing elements that match the contents of the file get updated upon load? I have done some research as to how the loading and saving .ini files works and i have not really grasped how the system works.

@sarisman84
Copy link
Author

Alright. After some testing and some refactoring, i managed to successfully load an .ini file before ImGui::NewFrame() was called. The LoadLayout now caches the current .ini file address when called, which then is used on the next frame before ImGui::NewFrame()

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
docking settings .ini persistance
Projects
None yet
Development

No branches or pull requests

3 participants