Move Style and Layout configuration to shared GUI library.
PiperOrigin-RevId: 840246253 Change-Id: Ic4664b62e86e70fd6780cd9eb885978064c5f585
This commit is contained in:
committed by
Copybara-Service
parent
5f59104877
commit
5ee8b646f7
@@ -22,6 +22,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <implot.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "experimental/platform/helpers.h"
|
||||
@@ -29,12 +30,123 @@
|
||||
|
||||
namespace mujoco::platform {
|
||||
|
||||
static constexpr int kToolsBarHeight = 48;
|
||||
static constexpr int kStatusBarHeight = 32;
|
||||
static constexpr float kOptionsRelWidth = 0.22f;
|
||||
static constexpr float kInspectorRelWidth = 0.18f;
|
||||
static constexpr float kInfoRelHeight = 0.3f;
|
||||
|
||||
static ImVec2 GetFlexElementSize(int num_cols) {
|
||||
const float width = (ImGui::GetContentRegionAvail().x / num_cols) -
|
||||
ImGui::GetStyle().FramePadding.x * 2;
|
||||
return ImVec2(width, 0);
|
||||
}
|
||||
|
||||
void SetupTheme(GuiTheme theme) {
|
||||
ImGuiStyle& s = ImGui::GetStyle();
|
||||
if (theme == GuiTheme::kDark) {
|
||||
ImGui::StyleColorsDark(&s);
|
||||
} else {
|
||||
ImGui::StyleColorsLight(&s);
|
||||
}
|
||||
s.FrameBorderSize = 1;
|
||||
}
|
||||
|
||||
ImVec4 ConfigureDockingLayout() {
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
|
||||
const ImVec2 dockspace_pos{
|
||||
viewport->WorkPos.x,
|
||||
viewport->WorkPos.y + kToolsBarHeight
|
||||
};
|
||||
const ImVec2 dockspace_size{
|
||||
viewport->WorkSize.x,
|
||||
viewport->WorkSize.y - kToolsBarHeight - kStatusBarHeight
|
||||
};
|
||||
|
||||
ImGuiID root = ImGui::GetID("Root");
|
||||
const bool first_time = (ImGui::DockBuilderGetNode(root) == nullptr);
|
||||
|
||||
if (first_time) {
|
||||
ImGui::DockBuilderRemoveNode(root);
|
||||
ImGui::DockBuilderAddNode(root, ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodeSize(root, dockspace_size);
|
||||
|
||||
// Slice up the main dock space.
|
||||
ImGuiID main = root;
|
||||
|
||||
ImGuiID options = 0;
|
||||
ImGui::DockBuilderSplitNode(main, ImGuiDir_Left, kOptionsRelWidth,
|
||||
&options, &main);
|
||||
|
||||
ImGuiID inspector = 0;
|
||||
ImGui::DockBuilderSplitNode(main, ImGuiDir_Right, kInspectorRelWidth,
|
||||
&inspector, &main);
|
||||
|
||||
ImGuiID info = 0;
|
||||
ImGui::DockBuilderSplitNode(inspector, ImGuiDir_Down, kInfoRelHeight,
|
||||
&info, &inspector);
|
||||
|
||||
ImGui::DockBuilderDockWindow("Dockspace", main);
|
||||
ImGui::DockBuilderDockWindow("Options", options);
|
||||
ImGui::DockBuilderDockWindow("Inspector", inspector);
|
||||
ImGui::DockBuilderDockWindow("Info", info);
|
||||
ImGui::DockBuilderFinish(root);
|
||||
}
|
||||
|
||||
// Create a dummy window filling the entire workspace in which we can perform
|
||||
// docking.
|
||||
ImGui::SetNextWindowPos(dockspace_pos);
|
||||
ImGui::SetNextWindowSize(dockspace_size);
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
|
||||
const ImGuiWindowFlags kWorkspaceFlags =
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBringToFrontOnFocus |
|
||||
ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBackground;
|
||||
|
||||
platform::ScopedStyle style;
|
||||
style.Var(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
style.Var(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
style.Var(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||
ImGui::Begin("Dockspace", nullptr, kWorkspaceFlags);
|
||||
style.Reset();
|
||||
|
||||
const ImGuiDockNodeFlags kDockSpaceFlags =
|
||||
ImGuiDockNodeFlags_PassthruCentralNode |
|
||||
ImGuiDockNodeFlags_NoDockingOverCentralNode |
|
||||
ImGuiDockNodeFlags_AutoHideTabBar;
|
||||
ImGui::DockSpace(root, ImVec2(0.0f, 0.0f), kDockSpaceFlags);
|
||||
ImGui::End();
|
||||
|
||||
const ImGuiWindowFlags kFixedFlags = ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoDocking;
|
||||
|
||||
// Toolbar is fixed at the top.
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos, ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, kToolsBarHeight), ImGuiCond_Always);
|
||||
ImGui::Begin("ToolBar", nullptr, kFixedFlags);
|
||||
ImGui::End();
|
||||
|
||||
// StatusBar is fixed at the bottom.
|
||||
ImGui::SetNextWindowPos(ImVec2(0, viewport->Size.y - kStatusBarHeight), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, kStatusBarHeight), ImGuiCond_Always);
|
||||
ImGui::Begin("StatusBar", nullptr, kFixedFlags);
|
||||
ImGui::End();
|
||||
|
||||
const int settings_width = dockspace_size.x * kOptionsRelWidth;
|
||||
const int inspector_width = dockspace_size.x * kInspectorRelWidth;
|
||||
const float workspace_x = dockspace_pos.x + settings_width;
|
||||
const float workspace_y = dockspace_pos.y;
|
||||
const float workspace_w = dockspace_size.x - settings_width - inspector_width;
|
||||
const float workspace_h = dockspace_size.y;
|
||||
return ImVec4(workspace_x, workspace_y, workspace_w, workspace_h);
|
||||
}
|
||||
|
||||
void SensorGui(const mjModel* model, const mjData* data) {
|
||||
ImPlot::PushStyleVar(ImPlotStyleVar_FitPadding, ImVec2(0.1f, 0.1f));
|
||||
if (ImPlot::BeginPlot("Sensors", ImVec2(-1, 0),
|
||||
|
||||
@@ -25,10 +25,37 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
|
||||
namespace mujoco::platform {
|
||||
|
||||
// Standard default UX themes for MuJoCo applications.
|
||||
enum class GuiTheme {
|
||||
kLight,
|
||||
kDark,
|
||||
};
|
||||
|
||||
// Updates the ImGui internal style state to match the requested theme.
|
||||
void SetupTheme(GuiTheme theme);
|
||||
|
||||
// Configures the ImGui docking module to the standard layout used by Studio.
|
||||
// This includes the following named sections:
|
||||
// "ToolBar": fixed size bar spanning the top of the window; for placing
|
||||
// buttons and other controls that are always needed.
|
||||
// "StatusBar": fixed size bar spanning the bottom of the window; for
|
||||
// placing information and controls that are always needed.
|
||||
// "Options": resizable section of the left; designed for GUI elements that
|
||||
// are used to configure the simulation (e.g. PhysicsGui).
|
||||
// "Inspector": resizable section of the right; designed for inspecting
|
||||
// or manipulating mjData elements (e.g. ControlsGui).
|
||||
// "Info": resizable section below the inspector; designed for displaying
|
||||
// basic simulation information (e.g. InfoGui); hidden by default.
|
||||
//
|
||||
// Returns the size and position of the remaining workspace area which can then
|
||||
// be used to place additional elements (e.g. floating charts).
|
||||
ImVec4 ConfigureDockingLayout();
|
||||
|
||||
// UX for controlling the physics simulation parameters (e.g. integrator,
|
||||
// solver, etc.) in mjModel.
|
||||
void PhysicsGui(mjModel* model, float min_width);
|
||||
|
||||
+12
-120
@@ -34,7 +34,6 @@
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <imgui_internal.h>
|
||||
#include <implot.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "experimental/platform/gui.h"
|
||||
@@ -122,12 +121,6 @@ static constexpr const char* ICON_NEXT_FRAME = ICON_FA_CARET_RIGHT;
|
||||
static constexpr const char* ICON_CURR_FRAME = ICON_FA_FAST_FORWARD;
|
||||
static constexpr const char* ICON_SPEED = ICON_FA_TACHOMETER;
|
||||
|
||||
static constexpr int kToolsBarHeight = 48;
|
||||
static constexpr int kStatusBarHeight = 32;
|
||||
static constexpr float kOptionsRelWidth = 0.22f;
|
||||
static constexpr float kInspectorRelWidth = 0.18f;
|
||||
static constexpr float kInfoRelHeight = 0.3f;
|
||||
|
||||
// UI labels for mjtLabel.
|
||||
static constexpr const char* kLabelNames[] = {
|
||||
"None", "Body", "Joint", "Geom", "Site", "Camera",
|
||||
@@ -758,8 +751,8 @@ void App::MoveCamera(platform::CameraMotion motion, mjtNum reldx, mjtNum reldy)
|
||||
}
|
||||
|
||||
void App::BuildGui() {
|
||||
SetupStyle(ui_.style);
|
||||
const ImVec4 workspace_rect = ConfigureDockingLayout();
|
||||
SetupTheme(ui_.theme);
|
||||
const ImVec4 workspace_rect = platform::ConfigureDockingLayout();
|
||||
|
||||
// Place charts in bottom right corner of the workspace.
|
||||
const ImVec2 chart_size(250, 250);
|
||||
@@ -890,114 +883,11 @@ void App::BuildGui() {
|
||||
}
|
||||
}
|
||||
|
||||
void App::SetupStyle(Style style) {
|
||||
if (tmp_.style_editor) {
|
||||
return;
|
||||
void App::SetupTheme(platform::GuiTheme theme) {
|
||||
if (!tmp_.style_editor) {
|
||||
platform::SetupTheme(theme);
|
||||
ui_.theme = theme;
|
||||
}
|
||||
|
||||
ImGuiStyle& s = ImGui::GetStyle();
|
||||
if (style == kDark) {
|
||||
ImGui::StyleColorsDark(&s);
|
||||
} else {
|
||||
ImGui::StyleColorsLight(&s);
|
||||
}
|
||||
s.FrameBorderSize = 1;
|
||||
ui_.style = style;
|
||||
}
|
||||
|
||||
ImVec4 App::ConfigureDockingLayout() {
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
|
||||
const ImVec2 dockspace_pos{
|
||||
viewport->WorkPos.x,
|
||||
viewport->WorkPos.y + kToolsBarHeight
|
||||
};
|
||||
const ImVec2 dockspace_size{
|
||||
viewport->WorkSize.x,
|
||||
viewport->WorkSize.y - kToolsBarHeight - kStatusBarHeight
|
||||
};
|
||||
|
||||
ImGuiID root = ImGui::GetID("Root");
|
||||
const bool first_time = (ImGui::DockBuilderGetNode(root) == nullptr);
|
||||
|
||||
if (first_time) {
|
||||
ImGui::DockBuilderRemoveNode(root);
|
||||
ImGui::DockBuilderAddNode(root, ImGuiDockNodeFlags_DockSpace);
|
||||
ImGui::DockBuilderSetNodeSize(root, dockspace_size);
|
||||
|
||||
// Slice up the main dock space.
|
||||
ImGuiID main = root;
|
||||
|
||||
ImGuiID options = 0;
|
||||
ImGui::DockBuilderSplitNode(main, ImGuiDir_Left, kOptionsRelWidth,
|
||||
&options, &main);
|
||||
|
||||
ImGuiID inspector = 0;
|
||||
ImGui::DockBuilderSplitNode(main, ImGuiDir_Right, kInspectorRelWidth,
|
||||
&inspector, &main);
|
||||
|
||||
ImGuiID info = 0;
|
||||
ImGui::DockBuilderSplitNode(inspector, ImGuiDir_Down, kInfoRelHeight,
|
||||
&info, &inspector);
|
||||
|
||||
ImGui::DockBuilderDockWindow("Dockspace", main);
|
||||
ImGui::DockBuilderDockWindow("Options", options);
|
||||
ImGui::DockBuilderDockWindow("Inspector", inspector);
|
||||
ImGui::DockBuilderDockWindow("Info", info);
|
||||
ImGui::DockBuilderFinish(root);
|
||||
}
|
||||
|
||||
// Create a dummy window filling the entire workspace in which we can perform
|
||||
// docking.
|
||||
ImGui::SetNextWindowPos(dockspace_pos);
|
||||
ImGui::SetNextWindowSize(dockspace_size);
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
|
||||
const ImGuiWindowFlags kWorkspaceFlags =
|
||||
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
|
||||
ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoBringToFrontOnFocus |
|
||||
ImGuiWindowFlags_NoNavFocus | ImGuiWindowFlags_NoBackground;
|
||||
|
||||
platform::ScopedStyle style;
|
||||
style.Var(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
style.Var(ImGuiStyleVar_WindowBorderSize, 0.0f);
|
||||
style.Var(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||
ImGui::Begin("Dockspace", nullptr, kWorkspaceFlags);
|
||||
style.Reset();
|
||||
|
||||
const ImGuiDockNodeFlags kDockSpaceFlags =
|
||||
ImGuiDockNodeFlags_PassthruCentralNode |
|
||||
ImGuiDockNodeFlags_NoDockingOverCentralNode |
|
||||
ImGuiDockNodeFlags_AutoHideTabBar;
|
||||
ImGui::DockSpace(root, ImVec2(0.0f, 0.0f), kDockSpaceFlags);
|
||||
ImGui::End();
|
||||
|
||||
const ImGuiWindowFlags kFixedFlags = ImGuiWindowFlags_NoTitleBar |
|
||||
ImGuiWindowFlags_NoMove |
|
||||
ImGuiWindowFlags_NoResize |
|
||||
ImGuiWindowFlags_NoScrollbar |
|
||||
ImGuiWindowFlags_NoDocking;
|
||||
|
||||
// Toolbar is fixed at the top.
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos, ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, kToolsBarHeight), ImGuiCond_Always);
|
||||
ImGui::Begin("ToolBar", nullptr, kFixedFlags);
|
||||
ImGui::End();
|
||||
|
||||
// StatusBar is fixed at the bottom.
|
||||
ImGui::SetNextWindowPos(ImVec2(0, viewport->Size.y - kStatusBarHeight), ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, kStatusBarHeight), ImGuiCond_Always);
|
||||
ImGui::Begin("StatusBar", nullptr, kFixedFlags);
|
||||
ImGui::End();
|
||||
|
||||
const int settings_width = dockspace_size.x * kOptionsRelWidth;
|
||||
const int inspector_width = dockspace_size.x * kInspectorRelWidth;
|
||||
const float workspace_x = dockspace_pos.x + settings_width;
|
||||
const float workspace_y = dockspace_pos.y;
|
||||
const float workspace_w = dockspace_size.x - settings_width - inspector_width;
|
||||
const float workspace_h = dockspace_size.y;
|
||||
return ImVec4(workspace_x, workspace_y, workspace_w, workspace_h);
|
||||
}
|
||||
|
||||
void App::ModelOptionsGui() {
|
||||
@@ -1246,11 +1136,13 @@ void App::ToolBarGui() {
|
||||
|
||||
// Style selection.
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ui_.style == kDark ? ICON_DARKMODE : ICON_LIGHTMODE)) {
|
||||
if (ui_.style == kDark) {
|
||||
SetupStyle(kLight);
|
||||
if (ImGui::Button(ui_.theme == platform::GuiTheme::kDark
|
||||
? ICON_DARKMODE
|
||||
: ICON_LIGHTMODE)) {
|
||||
if (ui_.theme == platform::GuiTheme::kDark) {
|
||||
SetupTheme(platform::GuiTheme::kLight);
|
||||
} else {
|
||||
SetupStyle(kDark);
|
||||
SetupTheme(platform::GuiTheme::kDark);
|
||||
}
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Switch Style");
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
#include <mujoco/mujoco.h>
|
||||
#include "experimental/platform/gui.h"
|
||||
#include "experimental/platform/helpers.h"
|
||||
#include "experimental/platform/interaction.h"
|
||||
#include "experimental/platform/renderer.h"
|
||||
@@ -65,18 +65,13 @@ class App {
|
||||
static int LoadAssetCallback(const char* path, void* user_data,
|
||||
unsigned char** out, std::uint64_t* out_size);
|
||||
|
||||
enum Style {
|
||||
kLight,
|
||||
kDark,
|
||||
};
|
||||
|
||||
// UI state that is persisted across application runs
|
||||
struct UiState {
|
||||
char watch_field[1000] = "qpos";
|
||||
int watch_index = 0;
|
||||
int camera_idx = platform::kTumbleCameraIdx;
|
||||
int key_idx = 0;
|
||||
Style style = kLight;
|
||||
platform::GuiTheme theme = platform::GuiTheme::kLight;
|
||||
|
||||
using Dict = std::unordered_map<std::string, std::string>;
|
||||
Dict ToDict() const;
|
||||
@@ -148,8 +143,7 @@ class App {
|
||||
void HandleKeyboardEvents();
|
||||
void MoveCamera(platform::CameraMotion motion, mjtNum reldx, mjtNum reldy);
|
||||
|
||||
void SetupStyle(Style style);
|
||||
ImVec4 ConfigureDockingLayout();
|
||||
void SetupTheme(platform::GuiTheme theme);
|
||||
|
||||
void MainMenuGui();
|
||||
void ToolBarGui();
|
||||
|
||||
Reference in New Issue
Block a user