Load last saved GUI configuration on first load.

Also save theme to the configuration.

PiperOrigin-RevId: 843710929
Change-Id: I7ce9ce0f026d2cb5f79addf6c16c9b540bf11954
This commit is contained in:
Haroon Qureshi
2025-12-12 08:55:57 -08:00
committed by Copybara-Service
parent 499291e5c2
commit 43bcbb158c
3 changed files with 35 additions and 7 deletions
+25 -5
View File
@@ -47,9 +47,12 @@ static constexpr const char ICON_FA_SUN[] = "\xEF\x86\x85";
static constexpr const char ICON_FA_TACHOMETER[] = "\xEF\x83\xA4";
static constexpr const char ICON_FA_UNDO[] = "\xEF\x83\xA2";
using KeyValues = std::unordered_map<std::string, std::string>;
// This is a workaround to fix compilation on gcc <= 12 and clang <= 16
template <typename T>
struct dependent_false : std::false_type {};
// Appends key/value pairs to an Ini file.
void AppendIniSection(std::string& ini, const std::string& section,
const KeyValues& key_values);
@@ -58,6 +61,27 @@ void AppendIniSection(std::string& ini, const std::string& section,
KeyValues ReadIniSection(const std::string& contents,
const std::string& section);
template <typename T>
T ReadIniValue(const KeyValues& key_values, const std::string& key, T def) {
auto iter = key_values.find(key);
if (iter == key_values.end()) {
return def;
}
if constexpr (std::is_same_v<T, int>) {
return std::stoi(iter->second);
} else if constexpr (std::is_same_v<T, float>) {
return std::stof(iter->second);
} else if constexpr (std::is_same_v<T, double>) {
return std::stod(iter->second);
} else if constexpr (std::is_same_v<T, std::string>) {
return iter->second;
} else if constexpr (std::is_enum_v<T>) {
return static_cast<T>(std::stoi(iter->second));
} else {
static_assert(dependent_false<T>::value, "Unsupported type");
}
}
// Helper class for setting ImGui style options; automatically resets the
// styles when going out of scope.
struct ScopedStyle {
@@ -179,10 +203,6 @@ struct ImGuiOpts {
const char* format = std::is_floating_point_v<T> ? "%.3g" : "%d";
};
// This is a workaround to fix compilation on gcc <= 12 and clang <= 16
template <typename T>
struct dependent_false : std::false_type {};
// A compile-time wrapper around ImGui::InputScalarN. This is useful because
// MuJoCo uses an `mjtNum` type which is an alias for float or double.
//
+9 -2
View File
@@ -742,7 +742,7 @@ void App::LoadSettings() {
if (!ini_path_.empty()) {
std::string settings = platform::LoadText(ini_path_);
if (!settings.empty()) {
ui_.FromDict(platform::ReadIniSection(settings, "[Simulate][Data]"));
ui_.FromDict(platform::ReadIniSection(settings, "[Studio][UX]"));
ImGui::LoadIniSettingsFromMemory(settings.data(), settings.size());
}
}
@@ -751,7 +751,7 @@ void App::LoadSettings() {
void App::SaveSettings() {
if (!ini_path_.empty()) {
std::string settings = ImGui::SaveIniSettingsToMemory();
platform::AppendIniSection(settings, "[Simulate][Data]", ui_.ToDict());
platform::AppendIniSection(settings, "[Studio][UX]", ui_.ToDict());
platform::SaveText(settings, ini_path_);
}
}
@@ -912,6 +912,10 @@ void App::BuildGui() {
}
ImGuiIO& io = ImGui::GetIO();
if (tmp_.first_frame) {
LoadSettings();
tmp_.first_frame = false;
}
if (io.WantSaveIniSettings) {
SaveSettings();
io.WantSaveIniSettings = false;
@@ -922,6 +926,7 @@ void App::SetupTheme(platform::GuiTheme theme) {
if (!tmp_.style_editor) {
platform::SetupTheme(theme);
ui_.theme = theme;
ImGui::GetIO().WantSaveIniSettings = true;
}
}
@@ -1747,11 +1752,13 @@ std::vector<const char*> App::GetCameraNames() {
App::UiState::Dict App::UiState::ToDict() const {
return {
{"theme", std::to_string(static_cast<int>(theme))},
};
}
void App::UiState::FromDict(const Dict& dict) {
*this = UiState();
theme = ReadIniValue(dict, "theme", theme);
}
int App::LoadAssetCallback(const char* path, void* user_data,
+1
View File
@@ -90,6 +90,7 @@ class App {
// UI state that is transient and only needed while the application runs
struct UiTempState {
bool should_exit = false;
bool first_frame = true;
// Windows.
bool help = false;