First pass at mjSpec Explorer and Properties windows.
Displays the list of bodies and joints from the mjSpec and displays values for the selected element. Functionality is very limited and a bit non-intuitive. However, we want to get this into our users hands to start getting feedback. PiperOrigin-RevId: 842228895 Change-Id: I2491cd5e0acaf622110e0f6b8406919024d3607a
This commit is contained in:
committed by
Copybara-Service
parent
c064abc3da
commit
97eb307ce9
@@ -33,8 +33,8 @@ namespace mujoco::platform {
|
|||||||
static constexpr int kToolsBarHeight = 48;
|
static constexpr int kToolsBarHeight = 48;
|
||||||
static constexpr int kStatusBarHeight = 32;
|
static constexpr int kStatusBarHeight = 32;
|
||||||
static constexpr float kOptionsRelWidth = 0.22f;
|
static constexpr float kOptionsRelWidth = 0.22f;
|
||||||
static constexpr float kInspectorRelWidth = 0.18f;
|
static constexpr float kInspectorRelWidth = 0.22f;
|
||||||
static constexpr float kInfoRelHeight = 0.3f;
|
static constexpr float kStatsRelHeight = 0.3f;
|
||||||
|
|
||||||
static ImVec2 GetFlexElementSize(int num_cols) {
|
static ImVec2 GetFlexElementSize(int num_cols) {
|
||||||
const float width = (ImGui::GetContentRegionAvail().x / num_cols) -
|
const float width = (ImGui::GetContentRegionAvail().x / num_cols) -
|
||||||
@@ -83,14 +83,20 @@ ImVec4 ConfigureDockingLayout() {
|
|||||||
ImGui::DockBuilderSplitNode(main, ImGuiDir_Right, kInspectorRelWidth,
|
ImGui::DockBuilderSplitNode(main, ImGuiDir_Right, kInspectorRelWidth,
|
||||||
&inspector, &main);
|
&inspector, &main);
|
||||||
|
|
||||||
ImGuiID info = 0;
|
ImGuiID stats = 0;
|
||||||
ImGui::DockBuilderSplitNode(inspector, ImGuiDir_Down, kInfoRelHeight,
|
ImGui::DockBuilderSplitNode(options, ImGuiDir_Down, kStatsRelHeight,
|
||||||
&info, &inspector);
|
&stats, &options);
|
||||||
|
|
||||||
|
ImGuiID properties = 0;
|
||||||
|
ImGui::DockBuilderSplitNode(inspector, ImGuiDir_Down, kStatsRelHeight,
|
||||||
|
&properties, &inspector);
|
||||||
|
|
||||||
ImGui::DockBuilderDockWindow("Dockspace", main);
|
ImGui::DockBuilderDockWindow("Dockspace", main);
|
||||||
ImGui::DockBuilderDockWindow("Options", options);
|
ImGui::DockBuilderDockWindow("Options", options);
|
||||||
|
ImGui::DockBuilderDockWindow("Explorer", inspector);
|
||||||
ImGui::DockBuilderDockWindow("Inspector", inspector);
|
ImGui::DockBuilderDockWindow("Inspector", inspector);
|
||||||
ImGui::DockBuilderDockWindow("Info", info);
|
ImGui::DockBuilderDockWindow("Properties", properties);
|
||||||
|
ImGui::DockBuilderDockWindow("Stats", stats);
|
||||||
ImGui::DockBuilderFinish(root);
|
ImGui::DockBuilderFinish(root);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -848,7 +854,8 @@ void CountsGui(const mjModel* model, mjData* data) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void InfoGui(const mjModel* model, const mjData* data, bool paused, float fps) {
|
void StatsGui(const mjModel* model, const mjData* data, bool paused,
|
||||||
|
float fps) {
|
||||||
const int num_islands = std::clamp(data->nisland, 1, mjNISLAND);
|
const int num_islands = std::clamp(data->nisland, 1, mjNISLAND);
|
||||||
|
|
||||||
// compute solver error (maximum over islands)
|
// compute solver error (maximum over islands)
|
||||||
@@ -916,4 +923,111 @@ void InfoGui(const mjModel* model, const mjData* data, bool paused, float fps) {
|
|||||||
ImGui::Columns();
|
ImGui::Columns();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BodyPropertiesGui(const mjModel* model, const mjData* data,
|
||||||
|
mjsElement* element, int id) {
|
||||||
|
const mjsBody* body = mjs_asBody(element);
|
||||||
|
|
||||||
|
ImGui::Columns(2);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.4f);
|
||||||
|
ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.6f);
|
||||||
|
|
||||||
|
std::string name = *mjs_getName(body->element);
|
||||||
|
if (name.empty()) {
|
||||||
|
name = "(Body " + std::to_string(id) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Columns(2);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.3f);
|
||||||
|
ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.7f);
|
||||||
|
|
||||||
|
ImGui::Text("Name");
|
||||||
|
ImGui::Text("xpos[0]");
|
||||||
|
ImGui::Text("xpos[1]");
|
||||||
|
ImGui::Text("xpos[2]");
|
||||||
|
ImGui::Text("xquat[0]");
|
||||||
|
ImGui::Text("xquat[1]");
|
||||||
|
ImGui::Text("xquat[2]");
|
||||||
|
ImGui::Text("xquat[3]");
|
||||||
|
ImGui::Text("mass");
|
||||||
|
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::Text("%s", name.c_str());
|
||||||
|
ImGui::Text("%f", data->xpos[3*id+0]);
|
||||||
|
ImGui::Text("%f", data->xpos[3*id+1]);
|
||||||
|
ImGui::Text("%f", data->xpos[3*id+2]);
|
||||||
|
ImGui::Text("%f", data->xquat[4*id+0]);
|
||||||
|
ImGui::Text("%f", data->xquat[4*id+1]);
|
||||||
|
ImGui::Text("%f", data->xquat[4*id+2]);
|
||||||
|
ImGui::Text("%f", data->xquat[4*id+3]);
|
||||||
|
ImGui::Text("%f", model->body_mass[id]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void JointPropertiesGui(const mjModel* model, const mjData* data,
|
||||||
|
mjsElement* element, int id) {
|
||||||
|
const mjsJoint* joint = mjs_asJoint(element);
|
||||||
|
|
||||||
|
ImGui::Columns(2);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.4f);
|
||||||
|
ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.6f);
|
||||||
|
|
||||||
|
std::string name = *mjs_getName(joint->element);
|
||||||
|
if (name.empty()) {
|
||||||
|
name = "(Joint " + std::to_string(id) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Columns(2);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.3f);
|
||||||
|
ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.7f);
|
||||||
|
ImGui::Text("Name");
|
||||||
|
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::Text("%s", name.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SitePropertiesGui(const mjModel* model, const mjData* data,
|
||||||
|
mjsElement* element, int id) {
|
||||||
|
const mjsSite* site = mjs_asSite(element);
|
||||||
|
|
||||||
|
ImGui::Columns(2);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.4f);
|
||||||
|
ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.6f);
|
||||||
|
|
||||||
|
std::string name = *mjs_getName(site->element);
|
||||||
|
if (name.empty()) {
|
||||||
|
name = "(Joint " + std::to_string(id) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::Columns(2);
|
||||||
|
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.3f);
|
||||||
|
ImGui::SetColumnWidth(1, ImGui::GetWindowWidth() * 0.7f);
|
||||||
|
ImGui::Text("Name");
|
||||||
|
ImGui::Text("site_xpos[0]");
|
||||||
|
ImGui::Text("site_xpos[1]");
|
||||||
|
ImGui::Text("site_xpos[2]");
|
||||||
|
ImGui::Text("site_xmat[0]");
|
||||||
|
ImGui::Text("site_xmat[1]");
|
||||||
|
ImGui::Text("site_xmat[2]");
|
||||||
|
ImGui::Text("site_xmat[3]");
|
||||||
|
ImGui::Text("site_xmat[4]");
|
||||||
|
ImGui::Text("site_xmat[5]");
|
||||||
|
ImGui::Text("site_xmat[6]");
|
||||||
|
ImGui::Text("site_xmat[7]");
|
||||||
|
ImGui::Text("site_xmat[8]");
|
||||||
|
|
||||||
|
ImGui::NextColumn();
|
||||||
|
ImGui::Text("%s", name.c_str());
|
||||||
|
ImGui::Text("%f", data->site_xpos[3*id+0]);
|
||||||
|
ImGui::Text("%f", data->site_xpos[3*id+1]);
|
||||||
|
ImGui::Text("%f", data->site_xpos[3*id+2]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+0]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+1]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+2]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+3]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+4]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+5]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+6]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+7]);
|
||||||
|
ImGui::Text("%f", data->site_xmat[4*id+8]);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace mujoco::platform
|
} // namespace mujoco::platform
|
||||||
|
|||||||
@@ -49,8 +49,13 @@ void SetupTheme(GuiTheme theme);
|
|||||||
// are used to configure the simulation (e.g. PhysicsGui).
|
// are used to configure the simulation (e.g. PhysicsGui).
|
||||||
// "Inspector": resizable section of the right; designed for inspecting
|
// "Inspector": resizable section of the right; designed for inspecting
|
||||||
// or manipulating mjData elements (e.g. ControlsGui).
|
// or manipulating mjData elements (e.g. ControlsGui).
|
||||||
// "Info": resizable section below the inspector; designed for displaying
|
// "Explorer": secondary tab connected to the Inspector; designed for
|
||||||
// basic simulation information (e.g. InfoGui); hidden by default.
|
// displaying the tree of mjSpec elements.
|
||||||
|
// "Stats": resizable section below the options; designed for displaying
|
||||||
|
// basic simulation statistics (e.g. StatsGui); hidden by default.
|
||||||
|
// "Properties": resizable section below the explorer; designed for displaying
|
||||||
|
// properties of mjSpec elements (e.g. BodyPropertiesGui); hidden by
|
||||||
|
// default.
|
||||||
//
|
//
|
||||||
// Returns the size and position of the remaining workspace area which can then
|
// Returns the size and position of the remaining workspace area which can then
|
||||||
// be used to place additional elements (e.g. floating charts).
|
// be used to place additional elements (e.g. floating charts).
|
||||||
@@ -108,7 +113,15 @@ void CountsGui(const mjModel* model, mjData* data);
|
|||||||
|
|
||||||
// UX for displaying basic simulation information. Note that the pause state and
|
// UX for displaying basic simulation information. Note that the pause state and
|
||||||
// FPS needs to be tracked by the caller and passed here to be displayed.
|
// FPS needs to be tracked by the caller and passed here to be displayed.
|
||||||
void InfoGui(const mjModel* model, const mjData* data, bool paused, float fps);
|
void StatsGui(const mjModel* model, const mjData* data, bool paused, float fps);
|
||||||
|
|
||||||
|
// UX for displaying properties of various mjSpec elements.
|
||||||
|
void BodyPropertiesGui(const mjModel* model, const mjData* data,
|
||||||
|
mjsElement* element, int id);
|
||||||
|
void JointPropertiesGui(const mjModel* model, const mjData* data,
|
||||||
|
mjsElement* element, int id);
|
||||||
|
void SitePropertiesGui(const mjModel* model, const mjData* data,
|
||||||
|
mjsElement* element, int id);
|
||||||
|
|
||||||
} // namespace mujoco::platform
|
} // namespace mujoco::platform
|
||||||
|
|
||||||
|
|||||||
@@ -44,6 +44,7 @@
|
|||||||
#include "experimental/platform/renderer.h"
|
#include "experimental/platform/renderer.h"
|
||||||
#include "experimental/platform/step_control.h"
|
#include "experimental/platform/step_control.h"
|
||||||
#include "experimental/platform/window.h"
|
#include "experimental/platform/window.h"
|
||||||
|
#include "xml/xml.h"
|
||||||
#include "xml/xml_api.h"
|
#include "xml/xml_api.h"
|
||||||
|
|
||||||
#if defined(USE_FILAMENT_OPENGL) || defined(USE_FILAMENT_VULKAN)
|
#if defined(USE_FILAMENT_OPENGL) || defined(USE_FILAMENT_VULKAN)
|
||||||
@@ -222,7 +223,10 @@ void App::ProcessPendingLoad() {
|
|||||||
if (model_file_.ends_with(".mjb")) {
|
if (model_file_.ends_with(".mjb")) {
|
||||||
model_ = mj_loadModel(model_file_.c_str(), 0);
|
model_ = mj_loadModel(model_file_.c_str(), 0);
|
||||||
} else if (model_file_.ends_with(".xml")) {
|
} else if (model_file_.ends_with(".xml")) {
|
||||||
model_ = mj_loadXML(model_file_.c_str(), nullptr, err, sizeof(err));
|
spec_ = ParseXML(model_file_.c_str(), nullptr, err, sizeof(err));
|
||||||
|
if (spec_ && err[0] == 0) {
|
||||||
|
model_ = mj_compile(spec_, nullptr);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
error_ = "Unknown model file type; expected .mjb or .xml.";
|
error_ = "Unknown model file type; expected .mjb or .xml.";
|
||||||
}
|
}
|
||||||
@@ -596,7 +600,7 @@ void App::HandleKeyboardEvents() {
|
|||||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_F1)) {
|
} else if (ImGui_IsChordJustPressed(ImGuiKey_F1)) {
|
||||||
ToggleWindow(tmp_.help);
|
ToggleWindow(tmp_.help);
|
||||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_F2)) {
|
} else if (ImGui_IsChordJustPressed(ImGuiKey_F2)) {
|
||||||
ToggleWindow(tmp_.info);
|
ToggleWindow(tmp_.stats);
|
||||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_F6)) {
|
} else if (ImGui_IsChordJustPressed(ImGuiKey_F6)) {
|
||||||
vis_options_.frame = (vis_options_.frame + 1) % mjNFRAME;
|
vis_options_.frame = (vis_options_.frame + 1) % mjNFRAME;
|
||||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_F7)) {
|
} else if (ImGui_IsChordJustPressed(ImGuiKey_F7)) {
|
||||||
@@ -806,6 +810,20 @@ void App::BuildGui() {
|
|||||||
DataInspectorGui();
|
DataInspectorGui();
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
|
|
||||||
|
bool explorer_is_open = false;
|
||||||
|
if (ImGui::Begin("Explorer", &tmp_.inspector_panel)) {
|
||||||
|
explorer_is_open = true;
|
||||||
|
SpecExplorerGui();
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
if (explorer_is_open && tmp_.element != nullptr) {
|
||||||
|
if (ImGui::Begin("Properties")) {
|
||||||
|
PropertiesGui();
|
||||||
|
}
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp_.chart_cpu_time) {
|
if (tmp_.chart_cpu_time) {
|
||||||
@@ -848,11 +866,11 @@ void App::BuildGui() {
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tmp_.info) {
|
if (tmp_.stats) {
|
||||||
platform::ScopedStyle style;
|
platform::ScopedStyle style;
|
||||||
style.Var(ImGuiStyleVar_Alpha, 0.6f);
|
style.Var(ImGuiStyleVar_Alpha, 0.6f);
|
||||||
if (ImGui::Begin("Info", &tmp_.info)) {
|
if (ImGui::Begin("Stats", &tmp_.stats)) {
|
||||||
platform::InfoGui(model_, data_, step_control_.IsPaused(), fps_);
|
platform::StatsGui(model_, data_, step_control_.IsPaused(), fps_);
|
||||||
}
|
}
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
@@ -931,6 +949,11 @@ void App::ModelOptionsGui() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void App::DataInspectorGui() {
|
void App::DataInspectorGui() {
|
||||||
|
if (data_ == nullptr) {
|
||||||
|
ImGui::Text("No mjData loaded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const float min_width = GetExpectedLabelWidth();
|
const float min_width = GetExpectedLabelWidth();
|
||||||
const ImGuiTreeNodeFlags flags =
|
const ImGuiTreeNodeFlags flags =
|
||||||
ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_Framed;
|
ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_Framed;
|
||||||
@@ -966,6 +989,112 @@ void App::DataInspectorGui() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DisplayElementTree(mjsElement* element) {
|
||||||
|
const mjString* name = mjs_getName(element);
|
||||||
|
if (name->empty()) {
|
||||||
|
ImGui::Text("(unnamed)");
|
||||||
|
} else {
|
||||||
|
ImGui::Text("%s", name->c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::SpecExplorerGui() {
|
||||||
|
if (spec_ == nullptr) {
|
||||||
|
ImGui::Text("No mjSpec loaded.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_SpanAvailWidth;
|
||||||
|
|
||||||
|
auto display_group = [this](mjtObj type, const std::string& prefix) {
|
||||||
|
mjsElement* element = mjs_firstElement(spec_, type);
|
||||||
|
while (element) {
|
||||||
|
const int id = mjs_getId(element);
|
||||||
|
|
||||||
|
const mjString* name = mjs_getName(element);
|
||||||
|
std::string label = *name;
|
||||||
|
if (label.empty()) {
|
||||||
|
label = "(" + prefix + " " + std::to_string(id) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Selectable(label.c_str(), false)) {
|
||||||
|
tmp_.element = element;
|
||||||
|
tmp_.element_id = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = mjs_nextElement(spec_, element);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
if (ImGui::TreeNodeEx("Bodies", flags)) {
|
||||||
|
// We don't use `display_group` here because we do additional selection
|
||||||
|
// logic tied to the `perturb_` field.
|
||||||
|
mjsElement* element = mjs_firstElement(spec_, mjOBJ_BODY);
|
||||||
|
while (element) {
|
||||||
|
const int id = mjs_getId(element);
|
||||||
|
|
||||||
|
const mjString* name = mjs_getName(element);
|
||||||
|
std::string label = *name;
|
||||||
|
if (label.empty()) {
|
||||||
|
label = "(Body " + std::to_string(id) + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Selectable(label.c_str(), (id == perturb_.select),
|
||||||
|
ImGuiSelectableFlags_AllowDoubleClick)) {
|
||||||
|
tmp_.element = element;
|
||||||
|
tmp_.element_id = id;
|
||||||
|
}
|
||||||
|
if (ImGui::IsItemHovered() && ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left)) {
|
||||||
|
perturb_.select = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
element = mjs_nextElement(spec_, element);
|
||||||
|
}
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TreeNodeEx("Joints", flags)) {
|
||||||
|
display_group(mjOBJ_JOINT, "Joint");
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::TreeNodeEx("Sites", flags)) {
|
||||||
|
display_group(mjOBJ_SITE, "Site");
|
||||||
|
ImGui::TreePop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void App::PropertiesGui() {
|
||||||
|
if (tmp_.element == nullptr) {
|
||||||
|
ImGui::Text("No element selected.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (tmp_.element->elemtype) {
|
||||||
|
case mjOBJ_BODY:
|
||||||
|
ImGui::Text("Body");
|
||||||
|
ImGui::Separator();
|
||||||
|
platform::BodyPropertiesGui(model_, data_, tmp_.element, tmp_.element_id);
|
||||||
|
break;
|
||||||
|
case mjOBJ_JOINT:
|
||||||
|
ImGui::Text("Joint");
|
||||||
|
ImGui::Separator();
|
||||||
|
platform::JointPropertiesGui(model_, data_, tmp_.element,
|
||||||
|
tmp_.element_id);
|
||||||
|
break;
|
||||||
|
case mjOBJ_SITE:
|
||||||
|
ImGui::Text("Site");
|
||||||
|
ImGui::Separator();
|
||||||
|
platform::SitePropertiesGui(model_, data_, tmp_.element,
|
||||||
|
tmp_.element_id);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// ignore other types
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void App::HelpGui() {
|
void App::HelpGui() {
|
||||||
ImGui::Columns(4);
|
ImGui::Columns(4);
|
||||||
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.35f);
|
ImGui::SetColumnWidth(0, ImGui::GetWindowWidth() * 0.35f);
|
||||||
@@ -974,7 +1103,7 @@ void App::HelpGui() {
|
|||||||
ImGui::SetColumnWidth(3, ImGui::GetWindowWidth() * 0.1f);
|
ImGui::SetColumnWidth(3, ImGui::GetWindowWidth() * 0.1f);
|
||||||
|
|
||||||
ImGui::Text("Help");
|
ImGui::Text("Help");
|
||||||
ImGui::Text("Info");
|
ImGui::Text("Stats");
|
||||||
ImGui::Text("Cycle Frames");
|
ImGui::Text("Cycle Frames");
|
||||||
ImGui::Text("Cycle Labels");
|
ImGui::Text("Cycle Labels");
|
||||||
ImGui::Text("Free Camera");
|
ImGui::Text("Free Camera");
|
||||||
@@ -1364,8 +1493,8 @@ void App::MainMenuGui() {
|
|||||||
if (ImGui::MenuItem("Help", "F1", tmp_.help)) {
|
if (ImGui::MenuItem("Help", "F1", tmp_.help)) {
|
||||||
ToggleWindow(tmp_.help);
|
ToggleWindow(tmp_.help);
|
||||||
}
|
}
|
||||||
if (ImGui::MenuItem("Info", "F2", tmp_.info)) {
|
if (ImGui::MenuItem("Stats", "F2", tmp_.stats)) {
|
||||||
ToggleWindow(tmp_.info);
|
ToggleWindow(tmp_.stats);
|
||||||
}
|
}
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
if (ImGui::MenuItem("Style Editor", "", tmp_.style_editor)) {
|
if (ImGui::MenuItem("Style Editor", "", tmp_.style_editor)) {
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ class App {
|
|||||||
|
|
||||||
// Windows.
|
// Windows.
|
||||||
bool help = false;
|
bool help = false;
|
||||||
bool info = false;
|
bool stats = false;
|
||||||
bool chart_cpu_time = false;
|
bool chart_cpu_time = false;
|
||||||
bool chart_dimensions = false;
|
bool chart_dimensions = false;
|
||||||
bool chart_solver = false;
|
bool chart_solver = false;
|
||||||
@@ -106,6 +106,10 @@ class App {
|
|||||||
std::vector<std::string> camera_names;
|
std::vector<std::string> camera_names;
|
||||||
std::vector<std::string> speed_names;
|
std::vector<std::string> speed_names;
|
||||||
|
|
||||||
|
// Spec Properties.
|
||||||
|
mjsElement* element = nullptr;
|
||||||
|
int element_id = -1;
|
||||||
|
|
||||||
// State.
|
// State.
|
||||||
int state_sig = 0;
|
int state_sig = 0;
|
||||||
std::vector<mjtNum> state;
|
std::vector<mjtNum> state;
|
||||||
@@ -152,6 +156,8 @@ class App {
|
|||||||
void FileDialogGui();
|
void FileDialogGui();
|
||||||
void ModelOptionsGui();
|
void ModelOptionsGui();
|
||||||
void DataInspectorGui();
|
void DataInspectorGui();
|
||||||
|
void SpecExplorerGui();
|
||||||
|
void PropertiesGui();
|
||||||
|
|
||||||
float GetExpectedLabelWidth();
|
float GetExpectedLabelWidth();
|
||||||
std::vector<const char*> GetCameraNames();
|
std::vector<const char*> GetCameraNames();
|
||||||
|
|||||||
Reference in New Issue
Block a user