Advertisement

Better option than using a static bool?

Started by September 16, 2024 01:37 AM
9 comments, last by taby 2 months, 3 weeks ago

I am trying to keep track of which ImGui tab is selected. Whenever the screens tab is selected, it retrieves the data from SQLite. The problem is, there's like 6 tabs, and keeping track of all those bools would be cumbersome. Is there a different method that's better?


		ImGui_ImplOpenGL3_NewFrame();
		ImGui_ImplSDL2_NewFrame(window);
		ImGui::NewFrame();

		ImGui::Begin("Debug");


		static bool screens_tab_was_selected = false;
		static vector<screen> vs;

		if (ImGui::BeginTabBar("##tabbar"), ImGuiTabBarFlags_::ImGuiTabBarFlags_NoTooltip)
		{
			ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;

			if (ImGui::BeginTabBar("MyTabBar", tab_bar_flags))
			{
				if (ImGui::BeginTabItem("Screens"))
				{
					if (screens_tab_was_selected == false)
					{
						vs = retrieve_screens("test.db");

						screens_tab_was_selected = true;

						cout << "retrieving screens" << endl;
					}

					vector<char*> vcharp(vs.size(), NULL);

					for (size_t i = 0; i < vs.size(); i++)
						vcharp[i] = const_cast<char*>(vs[i].nickname.c_str());
	
					static int selected = 0;
					if (ImGui::Combo("My Combo", &selected, &vcharp[0], vcharp.size()))
					{
						//MessageBoxA(NULL, vcharp[selected], "", MB_OK);
					}


					ImGui::EndTabItem();
				}
				if (ImGui::BeginTabItem("Characters"))
				{
					screens_tab_was_selected = false;

					ImGui::Text("Characters tab");
					ImGui::EndTabItem();
				}
				if (ImGui::BeginTabItem("Portal Pairs"))
				{
					screens_tab_was_selected = false;
					ImGui::Text("Portal pairs tab");
					ImGui::EndTabItem();
				}
				if (ImGui::BeginTabItem("Cinematics"))
				{
					screens_tab_was_selected = false;
					ImGui::Text("Cinematics");
					ImGui::EndTabItem();
				}
				if (ImGui::BeginTabItem("Global booleans"))
				{
					screens_tab_was_selected = false;
					ImGui::Text("Global booleans");
					ImGui::EndTabItem();
				}
				ImGui::EndTabBar();
			}
		}

		ImGui::End();





	//	ImGui::ShowDemoWindow();





		ImGui::Render();
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

taby said:
keeping track of all those bools would be cumbersome. Is there a different method that's better?

If you need to track all the state, you loose the convenience of an immediate mode GUI in any case.

Personally i use some kind if configuration files to store settings on disk, and i have automated GUI generation from its data.
Settign it up looks liek this:

		void MakeConfig () // called from constructor of editor application class
		{
			config = Configuration("EditorApplication", "configs\\", 0, true);//false);//

			config.BeginScope ("Startup:", 0);
				config.SetParamI ("background threads", 15);
				config.SetParamString ("prefabDirectory", "c:\\dev\\data\\prefabs\\");
				config.SetParamString ("load staticMesh0", "sponza8k", 0, true);
				config.SetParamString ("load staticMesh1", "Armadillo_input", 0, true);
				config.SetParamString ("load staticMesh2", "sphere", 0, true);
				config.SetParamString ("load staticMesh3", "botijo", 0, true);
				config.SetParamFN ("activeRegion.minmax[0]", std::array<float,3>{-100.f, -100.0f, -100.0f}.data(), 3);
				config.SetParamFN ("activeRegion.minmax[1]", std::array<float,3>{100.f, 100.f, 100.f}.data(), 3);
				
				config.SetParamB ("start background processing at startup", 0);
				config.SetParamB ("procedural fluid scene at startup", 1);
				config.SetParamB ("fluid from file at startup", 1);
				config.SetParamB ("fluid to scene at startup", 0);
				config.SetParamB ("hm from file at startup", 0);

			config.EndScope ();

			

			config.LoadFromFile("", 0); // loads former data from disk. data is saved automatically in Configuration deconstructor
		}

This pushes the data with given default to std::vector, but then eventually loads from disk if already existing.

To show the GUI and getting the data i do this in another place:

void MainLoop (ApplicationFramework::Application &application, const matrix &cameraMatrix)
{
	ImGui::Begin("EditorApplication::MainLoop()");

	config.GUI(true); // automatically creates all the GUI elements for the data, using the data itself instead static variables
			

	activeRegion.minmax[0] = vec( // example to get some of the data
				config.GetParamF("activeRegion.minmax[0]", -600.f, 0),
				config.GetParamF("activeRegion.minmax[0]", -600.f, 1),
				config.GetParamF("activeRegion.minmax[0]", -600.f, 2));
}

That's probably as convenient as it can get. It's not more code than writing IMGUI calls where needed.

But because i need to define the data in advance during some initialization, it still feels more cumbersome than using the static variables in place.

So in practice, usually i still begin with static variables, and only if stuff becomes way too much i finally replace it with a configuration file. I know i should do this from the start, but i tend to refuse initially.
Probably the reason is that i always need to look at older code to have an example on how to setup the data. E.g. the syntax to make drop down boxes, or setting default tweaking step sizes, etc. is all compact one liners but hard to remember.
So i do copy paste from older code to have examples for those detail things.

If you do something similar, maybe make sure intellisense is good enough to use it, and no further knowledge is needed.

Also, ofc. this is limited regarding complex GUI design. I have support to group stuff using treeView for example, but i could not to tabs this way.

Advertisement

I ended up using an enum.

You're going to have so many variables, temporary or global or static, to run your system inevitably, so just make sure you keep them neatly somewhere logical, you can fit them into a structure is neat but makes them take longer to type out. Having less is more, eventually you kill your name space!

@taby To keep track of which ImGui tab is selected without using multiple boolean flags, you can use a more efficient approach. Here are a few better methods:

Using Tab Index
Using ImGui::TabItemButton()
Using ImGui::GetCurrentTabId()

Thank you for the comments, y’all.

Advertisement

Is there any way to programatically select a certain row in the combo box?

I guess this should work?

static int selected = 0;
if (program_rules) selected = program_desire;
ImGui::Combo("", &selected, ...);

Yes sir, that worked like a charm! Thanks again. Sorry that it was so obvious a fix.

So my SQL to select from the screens table values that are ordered by nickname.

I am having no luck. Any ideas?

		enum selected_tab { no_tab, screens_tab, portals_tab, portal_pairs_tab };
		static selected_tab sel_tab = no_tab;
		static vector<screen> vs;
		static vector<screen> last_vs;
		static int combo_selected = 0;

		static screen s;
		static string prev_s_nickname;
		static string last_id_string = "";


		ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;


		if (ImGui::BeginTabBar("TabBar", tab_bar_flags))
		{
			if (ImGui::BeginTabItem("Screens"))
			{
				bool updated = false;

				if (sel_tab != screens_tab)
				{
					vs = retrieve_screen_ids_and_nicknames("test.db");

					for (size_t i = 0; i < vs.size(); i++)
					{
						vs[i].nickname += " - ID: ";
						vs[i].nickname += to_string(vs[i].screen_id);
					}

					if (vs.size() > 0)
					{
						s = retrieve_screen_everything("test.db", vs[combo_selected].screen_id);
					}

					sel_tab = screens_tab;
					updated = true;
				}




// THIS IS WHERE IT FAILS
				if (!vector_screen_equals(last_vs, vs))
				{
					const string new_id_string = vs[combo_selected].nickname;

					cout << new_id_string << " " << last_id_string << endl;

					if (last_id_string != new_id_string)
					{
						for (size_t i = 0; i < vs.size(); i++)
						{
							if (last_id_string == vs[i].nickname)
							{
								cout << "found match" << endl;

								combo_selected = i;
								break;
							}
						}
					}

					last_id_string = new_id_string;
				}

				last_vs = vs;






				if (ImGui::Button("New"))
				{
					screen new_screen;
					new_screen.nickname = "New screen";
					insert_screen("test.db", new_screen);
					sel_tab = no_tab;
					//combo_selected = vcharp.size();
				}











				vector<char*> vcharp(vs.size(), NULL);

				for (size_t i = 0; i < vs.size(); i++)
					vcharp[i] = const_cast<char*>(vs[i].nickname.c_str());

				if (ImGui::Combo("Screens", &combo_selected, &vcharp[0], vcharp.size()))
				{
					cout << combo_selected << endl;

					if (vs.size() > 0)
						s = retrieve_screen_everything("test.db", vs[combo_selected].screen_id);// atoi(tokens[tokens.size() - 1].c_str()));

					ImGui::EndCombo();
				}




				//string s_id = to_string(s.screen_id);
				//ImGui::InputText("ID: ", &s_id, ImGuiInputTextFlags_ReadOnly);

				ImGui::InputText("Nickname", &s.nickname);

				if (prev_s_nickname != s.nickname)
				{
					update_nickname("test.db", s.screen_id, s.nickname);

					prev_s_nickname = s.nickname;
					sel_tab = no_tab;
				}





				ImGui::EndTabItem();
			}
			if (ImGui::BeginTabItem("Portals"))
			{
				sel_tab = portals_tab;
				ImGui::Text("Portals tab");
				ImGui::EndTabItem();
			}
			if (ImGui::BeginTabItem("Portal Pairs"))
			{
				sel_tab = portal_pairs_tab;
				ImGui::Text("Portal pairs tab");
				ImGui::EndTabItem();
			}

			//if (ImGui::BeginTabItem("Characters"))
			//{
			//	screens_tab_was_selected = false;

			//	ImGui::Text("Characters tab");
			//	ImGui::EndTabItem();
			//}

			//if (ImGui::BeginTabItem("Cinematics"))
			//{
			//	screens_tab_was_selected = false;
			//	ImGui::Text("Cinematics");
			//	ImGui::EndTabItem();
			//}
			//if (ImGui::BeginTabItem("Global booleans"))
			//{
			//	screens_tab_was_selected = false;
			//	ImGui::Text("Global booleans");
			//	ImGui::EndTabItem();
			//}




			ImGui::EndTabBar();

		}

		//		ImGui::InputText("test", &x);




		ImGui::End();





		// Rendering
		ImGui::Render();
		ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());

		SDL_GL_SwapWindow(window);
	}

This topic is closed to new replies.

Advertisement