Replicate the controls from the toolbar into the collapsible options sections and provides an option to hide the toolbar.
PiperOrigin-RevId: 937290592 Change-Id: I08f1f4880fd0b06123e817cb9ae7a3281daa8063
This commit is contained in:
committed by
Copybara-Service
parent
3d09a46d61
commit
0402bae176
@@ -352,7 +352,7 @@ void RescaleDock(float ratio) {
|
||||
}
|
||||
}
|
||||
|
||||
ImVec4 ConfigureDockingLayout() {
|
||||
ImVec4 ConfigureDockingLayout(bool show_toolbar, bool show_status_bar) {
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
const float scale = ImGui::GetWindowDpiScale();
|
||||
const float font_scale = ImGui::GetIO().FontGlobalScale;
|
||||
@@ -360,8 +360,10 @@ ImVec4 ConfigureDockingLayout() {
|
||||
const float kOptionsRelWidth = 0.15f;
|
||||
const float kInspectorRelWidth = 0.22f;
|
||||
const float kPropertiesRelHeight = 0.3f;
|
||||
const float kToolsBarHeight = 36.f * scale * font_scale;
|
||||
const float kStatusBarHeight = 32.f * scale * font_scale;
|
||||
const float kToolsBarHeight =
|
||||
show_toolbar ? 36.f * scale * font_scale : 0.0f;
|
||||
const float kStatusBarHeight =
|
||||
show_status_bar ? 32.f * scale * font_scale : 0.0f;
|
||||
|
||||
const ImVec2 dockspace_pos{viewport->WorkPos.x,
|
||||
viewport->WorkPos.y + kToolsBarHeight};
|
||||
@@ -437,23 +439,23 @@ ImVec4 ConfigureDockingLayout() {
|
||||
}
|
||||
|
||||
// Toolbar is fixed at the top.
|
||||
{
|
||||
if (show_toolbar) {
|
||||
platform::ScopedStyle style;
|
||||
style.Var(ImGuiStyleVar_WindowBorderSize, 1.0f);
|
||||
style.Var(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
style.Var(ImGuiStyleVar_WindowMinSize, ImVec2(1, 1));
|
||||
const float toolbar_vpad =
|
||||
std::max(0.f, (kToolsBarHeight - ImGui::GetFrameHeight()) * 0.5f);
|
||||
std::max(0.f, (36.f * scale * font_scale - ImGui::GetFrameHeight()) * 0.5f);
|
||||
style.Var(ImGuiStyleVar_WindowPadding, ImVec2(4 * scale, toolbar_vpad));
|
||||
ImGui::SetNextWindowPos(viewport->WorkPos, ImGuiCond_Always);
|
||||
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, kToolsBarHeight),
|
||||
ImGui::SetNextWindowSize(ImVec2(viewport->Size.x, 36.f * scale * font_scale),
|
||||
ImGuiCond_Always);
|
||||
ImGui::Begin("ToolBar", nullptr, kFixedFlags);
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// StatusBar is fixed at the bottom.
|
||||
{
|
||||
if (show_status_bar) {
|
||||
platform::ScopedStyle style;
|
||||
style.Var(ImGuiStyleVar_WindowBorderSize, 1.0f);
|
||||
style.Var(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
@@ -632,7 +634,7 @@ bool FrameSelectionGui(mjvOption* opts) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
static std::string GetCameraName(const mjModel* model, const mjvCamera& camera,
|
||||
std::string GetCameraName(const mjModel* model, const mjvCamera& camera,
|
||||
int index) {
|
||||
static constexpr char kCameraTumbleName[] = "Free: tumble";
|
||||
static constexpr char kCameraWasdName[] = "Free: wasd";
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
// mjvOption, etc. But, some functions take additional arguments as needed.
|
||||
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <imgui.h>
|
||||
@@ -67,7 +68,7 @@ void RescaleDock(float ratio);
|
||||
//
|
||||
// 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();
|
||||
ImVec4 ConfigureDockingLayout(bool show_toolbar = true, bool show_status_bar = false);
|
||||
|
||||
// logarithmically spaced real-time slow-down coefficients (percent)
|
||||
// clang-format off
|
||||
@@ -98,6 +99,10 @@ bool LabelSelectionGui(mjvOption* opts);
|
||||
// UX for selecting the visualization frame option.
|
||||
bool FrameSelectionGui(mjvOption* opts);
|
||||
|
||||
// Get the display name for a camera given its index.
|
||||
std::string GetCameraName(const mjModel* model, const mjvCamera& camera,
|
||||
int index);
|
||||
|
||||
// UX for selecting the camera.
|
||||
bool CameraSelectionGui(const mjModel* model, mjData* data, mjvCamera& camera,
|
||||
int& index);
|
||||
|
||||
@@ -69,7 +69,9 @@ static constexpr const char ICON_FA_CIRCLE_O[] = "\xEF\x84\x8C";
|
||||
static constexpr const char ICON_FA_CIRCLE[] = "\xEF\x84\x91";
|
||||
static constexpr const char ICON_FA_COMMENT[] = "\xEF\x83\xA5";
|
||||
static constexpr const char ICON_FA_COPY[] = "\xEF\x83\x85";
|
||||
static constexpr const char ICON_FA_CROSSHAIRS[] = "\xEF\x81\x9B";
|
||||
static constexpr const char ICON_FA_DIAMOND[] = "\xEF\x88\x99";
|
||||
static constexpr const char ICON_FA_DOWNLOAD[] = "\xEF\x80\x99";
|
||||
static constexpr const char ICON_FA_EJECT[] = "\xEF\x81\x92";
|
||||
static constexpr const char ICON_FA_FAST_FORWARD[] = "\xEF\x81\x90";
|
||||
static constexpr const char ICON_FA_MAGIC[] = "\xEF\x83\x90";
|
||||
@@ -84,6 +86,7 @@ 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_TRASH_CAN[] = "\xEF\x87\xB8";
|
||||
static constexpr const char ICON_FA_UNDO[] = "\xEF\x83\xA2";
|
||||
static constexpr const char ICON_FA_UPLOAD[] = "\xEF\x82\x93";
|
||||
|
||||
using KeyValues = std::unordered_map<std::string, std::string>;
|
||||
|
||||
|
||||
+351
-56
@@ -635,7 +635,12 @@ void App::HandleKeyboardEvents() {
|
||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_Q | ImGuiMod_Ctrl)) {
|
||||
tmp_.should_exit = true;
|
||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_A | ImGuiMod_Ctrl)) {
|
||||
mjv_defaultFreeCamera(model(), &camera_);
|
||||
const int cam_id = model()->vis.global.cameraid;
|
||||
if (cam_id >= 0 && cam_id < model()->ncam) {
|
||||
ui_.camera_idx = platform::SetCamera(model(), &camera_, cam_id);
|
||||
} else {
|
||||
mjv_defaultFreeCamera(model(), &camera_);
|
||||
}
|
||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_Tab | ImGuiMod_Shift)) {
|
||||
tmp_.inspector_panel = !tmp_.inspector_panel;
|
||||
} else if (ImGui_IsChordJustPressed(ImGuiKey_Tab)) {
|
||||
@@ -890,7 +895,7 @@ void App::BuildGui() {
|
||||
|
||||
ImGui::GetIO().FontGlobalScale = ui_.font_scale;
|
||||
|
||||
const ImVec4 workspace_rect = platform::ConfigureDockingLayout();
|
||||
const ImVec4 workspace_rect = platform::ConfigureDockingLayout(tmp_.toolbar, tmp_.status_bar);
|
||||
|
||||
// Place charts in bottom right corner of the workspace.
|
||||
const ImVec2 chart_size(250, 500);
|
||||
@@ -899,14 +904,14 @@ void App::BuildGui() {
|
||||
|
||||
MainMenuGui();
|
||||
|
||||
{
|
||||
if (tmp_.toolbar) {
|
||||
if (ImGui::Begin("ToolBar")) {
|
||||
ToolBarGui();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
{
|
||||
if (tmp_.status_bar) {
|
||||
platform::ScopedStyle style;
|
||||
style.Var(ImGuiStyleVar_CellPadding, ImVec2(0, 0));
|
||||
style.Var(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
|
||||
@@ -1075,6 +1080,225 @@ void App::ModelOptionsGui() {
|
||||
const ImGuiTreeNodeFlags node_flags =
|
||||
ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_Framed;
|
||||
|
||||
ImGui::BeginChild("SimulationGui", {0, 0}, child_flags);
|
||||
if (platform::SectionHeader(
|
||||
"Simulation", node_flags | ImGuiTreeNodeFlags_DefaultOpen, 0.65f)) {
|
||||
ImGui::PushID("SimSection");
|
||||
|
||||
const float slider_w = -ImGui::CalcTextSize(" Keyframe").x -
|
||||
ImGui::GetStyle().ItemInnerSpacing.x;
|
||||
|
||||
bool is_dark = ImGui::GetStyle().Colors[ImGuiCol_WindowBg].x < 0.5f;
|
||||
const ImColor green =
|
||||
is_dark ? ImColor(40, 125, 60, 255) : ImColor(40, 180, 40, 255);
|
||||
const ImColor yellow =
|
||||
is_dark ? ImColor(158, 115, 18, 255) : ImColor(255, 215, 0, 255);
|
||||
|
||||
// Reset / Reload / Align buttons.
|
||||
{
|
||||
char reset_label[32];
|
||||
std::snprintf(reset_label, sizeof(reset_label), "%s Reset",
|
||||
platform::ICON_FA_UNDO);
|
||||
char reload_label[32];
|
||||
std::snprintf(reload_label, sizeof(reload_label), "%s Reload",
|
||||
platform::ICON_FA_REFRESH);
|
||||
char align_label[32];
|
||||
std::snprintf(align_label, sizeof(align_label), "%s Align",
|
||||
platform::ICON_FA_CROSSHAIRS);
|
||||
|
||||
const float avail = ImGui::GetContentRegionAvail().x;
|
||||
const float spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||
const float btn_w = (avail - spacing * 2) / 3.0f;
|
||||
|
||||
if (ImGui::Button(reset_label, ImVec2(btn_w, 0))) {
|
||||
ResetPhysics();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(reload_label, ImVec2(btn_w, 0))) {
|
||||
RequestModelReload();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(align_label, ImVec2(btn_w, 0))) {
|
||||
const int cam_id = model()->vis.global.cameraid;
|
||||
if (cam_id >= 0 && cam_id < model()->ncam) {
|
||||
ui_.camera_idx = platform::SetCamera(model(), &camera_, cam_id);
|
||||
} else {
|
||||
mjv_defaultFreeCamera(model(), &camera_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pause / Run toggle.
|
||||
{
|
||||
ImGui::Spacing();
|
||||
char pause_label[32];
|
||||
std::snprintf(pause_label, sizeof(pause_label), "%s Pause",
|
||||
platform::ICON_FA_PAUSE);
|
||||
char run_label[32];
|
||||
std::snprintf(run_label, sizeof(run_label), "%s Run",
|
||||
platform::ICON_FA_PLAY);
|
||||
|
||||
bool paused = step_control_.GetPauseState() != PauseState::kUnpaused;
|
||||
bool running = step_control_.GetPauseState() == PauseState::kUnpaused;
|
||||
|
||||
const float avail = ImGui::GetContentRegionAvail().x;
|
||||
const float half = avail * 0.5f;
|
||||
const float h = ImGui::GetFrameHeight() * 1.4f;
|
||||
|
||||
ImGui::SetWindowFontScale(1.3f);
|
||||
if (platform::ImGui_ColorButtonEx(pause_label, paused, yellow,
|
||||
ImDrawFlags_RoundCornersLeft,
|
||||
ImVec2(half, h))) {
|
||||
step_control_.SetPauseState(PauseState::kNormalPaused);
|
||||
}
|
||||
ImGui::SameLine(0.f, 0.f);
|
||||
if (platform::ImGui_ColorButtonEx(run_label, running, green,
|
||||
ImDrawFlags_RoundCornersRight,
|
||||
ImVec2(half, h))) {
|
||||
step_control_.SetPauseState(PauseState::kUnpaused);
|
||||
}
|
||||
ImGui::SetWindowFontScale(1.0f);
|
||||
}
|
||||
|
||||
// Speed slider.
|
||||
{
|
||||
const int max_idx = platform::kPercentRealTime.size() - 1;
|
||||
int slider_val = max_idx - tmp_.speed_index;
|
||||
float speed_pct =
|
||||
std::stof(platform::kPercentRealTime[tmp_.speed_index]);
|
||||
|
||||
char fmt[64];
|
||||
const float desired = step_control_.GetSpeed();
|
||||
const float measured = step_control_.GetSpeedMeasured();
|
||||
bool misaligned = std::abs(measured - desired) > 0.1f * desired;
|
||||
if (misaligned) {
|
||||
std::snprintf(fmt, sizeof(fmt), "%.1f%%%% (%.1f%%%%)",
|
||||
speed_pct, measured);
|
||||
} else {
|
||||
std::snprintf(fmt, sizeof(fmt), "%.1f%%%%", speed_pct);
|
||||
}
|
||||
|
||||
ImGui::SetNextItemWidth(slider_w);
|
||||
if (ImGui::SliderInt("Speed", &slider_val, 0, max_idx, fmt)) {
|
||||
SetSpeedIndex(max_idx - slider_val);
|
||||
}
|
||||
if (misaligned) {
|
||||
ImGui::SetItemTooltip("%s", "Desired Speed (Measured Speed)");
|
||||
} else {
|
||||
ImGui::SetItemTooltip("%s", "Percent of real-time");
|
||||
}
|
||||
}
|
||||
|
||||
// History controls (Frame Scrubber).
|
||||
{
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
char prev_label[32];
|
||||
std::snprintf(prev_label, sizeof(prev_label), "%s Step Back", ICON_PREV_FRAME);
|
||||
char next_label[32];
|
||||
std::snprintf(next_label, sizeof(next_label), "%s Step Fwd", ICON_NEXT_FRAME);
|
||||
|
||||
const float avail = ImGui::GetContentRegionAvail().x;
|
||||
const float spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||
const float btn_w = (avail - spacing) / 2.0f;
|
||||
|
||||
if (ImGui::Button(prev_label, ImVec2(btn_w, 0))) {
|
||||
LoadHistory(sim_history_.GetIndex() - 1);
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Load previous frame from history");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(next_label, ImVec2(btn_w, 0))) {
|
||||
if (sim_history_.GetIndex() == 0) {
|
||||
step_control_.RequestSingleStep();
|
||||
} else {
|
||||
LoadHistory(sim_history_.GetIndex() + 1);
|
||||
}
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Load next frame from history / Single step");
|
||||
|
||||
ImGui::SetNextItemWidth(slider_w);
|
||||
int index = sim_history_.GetIndex();
|
||||
if (ImGui::SliderInt("History", &index, 1 - sim_history_.Size(), 0)) {
|
||||
LoadHistory(index);
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Scrub through simulation history");
|
||||
}
|
||||
|
||||
// Keyframe controls.
|
||||
if (model()->nkey > 0) {
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
{
|
||||
char key_fmt[128];
|
||||
const char* key_name =
|
||||
model()->names + model()->name_keyadr[ui_.key_idx];
|
||||
if (key_name[0] != '\0') {
|
||||
std::snprintf(key_fmt, sizeof(key_fmt), "%s", key_name);
|
||||
} else {
|
||||
std::snprintf(key_fmt, sizeof(key_fmt), "Key %d", ui_.key_idx);
|
||||
}
|
||||
ImGui::SetNextItemWidth(slider_w);
|
||||
ImGui::SliderInt("Keyframe", &ui_.key_idx, 0, model()->nkey - 1,
|
||||
key_fmt);
|
||||
}
|
||||
|
||||
// Keyframe buttons.
|
||||
{
|
||||
char load_label[32];
|
||||
std::snprintf(load_label, sizeof(load_label), "%s Load key",
|
||||
platform::ICON_FA_DOWNLOAD);
|
||||
char save_label[32];
|
||||
std::snprintf(save_label, sizeof(save_label), "%s Save key",
|
||||
platform::ICON_FA_UPLOAD);
|
||||
char copy_label[32];
|
||||
std::snprintf(copy_label, sizeof(copy_label), "%s Copy key",
|
||||
platform::ICON_FA_COPY);
|
||||
|
||||
const float avail = ImGui::GetContentRegionAvail().x;
|
||||
const float spacing = ImGui::GetStyle().ItemSpacing.x;
|
||||
const float btn_w = (avail - spacing * 2) / 3.0f;
|
||||
|
||||
if (ImGui::Button(load_label, ImVec2(btn_w, 0))) {
|
||||
mj_resetDataKeyframe(model(), data(), ui_.key_idx);
|
||||
mj_forward(model(), data());
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Load selected keyframe to active state");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(save_label, ImVec2(btn_w, 0))) {
|
||||
mj_setKeyframe(model(), data(), ui_.key_idx);
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Save active state to selected keyframe");
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(copy_label, ImVec2(btn_w, 0))) {
|
||||
std::string str = platform::KeyframeToString(model(), data(), false);
|
||||
platform::MaybeSaveToClipboard(str);
|
||||
}
|
||||
ImGui::SetItemTooltip(
|
||||
"%s", "Copy selected keyframe to clipboard as MJCF XML");
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
// Thread control.
|
||||
ImGui::SetNextItemWidth(slider_w);
|
||||
ImGui::BeginDisabled(std::thread::hardware_concurrency() <= 1);
|
||||
if (ImGui::SliderInt("Threads", &ui_.nthread, 0, 8, "%d worker threads")) {
|
||||
tmp_.update_threadpool = true;
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
ImGui::SetItemTooltip("%s", "Number of worker threads in threadpool");
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::PopID();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::BeginChild("PhysicsGui", {0, 0}, child_flags);
|
||||
if (platform::SectionHeader("Physics", node_flags, 0.65f)) {
|
||||
platform::PhysicsGui(model(), min_width);
|
||||
@@ -1084,6 +1308,96 @@ void App::ModelOptionsGui() {
|
||||
|
||||
ImGui::BeginChild("RenderingGui", {0, 0}, child_flags);
|
||||
if (platform::SectionHeader("Rendering", node_flags, 0.65f)) {
|
||||
ImGui::PushID("RenderingSection");
|
||||
|
||||
// Compute combo width so labels align on the right.
|
||||
char frame_label_tmp[32];
|
||||
std::snprintf(frame_label_tmp, sizeof(frame_label_tmp), " %s Camera",
|
||||
platform::ICON_FA_CAMERA);
|
||||
const float combo_w =
|
||||
-ImGui::CalcTextSize(frame_label_tmp).x -
|
||||
ImGui::GetStyle().ItemInnerSpacing.x;
|
||||
|
||||
// Camera selector.
|
||||
{
|
||||
std::string cam_name =
|
||||
platform::GetCameraName(model(), camera_, ui_.camera_idx);
|
||||
|
||||
char camera_text[32];
|
||||
std::snprintf(camera_text, sizeof(camera_text), "%s Camera",
|
||||
platform::ICON_FA_CAMERA);
|
||||
|
||||
ImGui::SetNextItemWidth(combo_w);
|
||||
if (ImGui::BeginCombo(camera_text, cam_name.c_str())) {
|
||||
auto select = [&](int idx) {
|
||||
std::string name =
|
||||
platform::GetCameraName(model(), camera_, idx);
|
||||
if (ImGui::Selectable(name.c_str(), (ui_.camera_idx == idx))) {
|
||||
ui_.camera_idx = platform::SetCamera(model(), &camera_, idx);
|
||||
}
|
||||
};
|
||||
select(platform::kTumbleCameraIdx);
|
||||
select(platform::kFreeCameraIdx);
|
||||
select(platform::kTrackingCameraIdx);
|
||||
for (int c = 0; c < model()->ncam; c++) {
|
||||
select(c);
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
// Label selector.
|
||||
{
|
||||
char label_text[32];
|
||||
std::snprintf(label_text, sizeof(label_text), "%s Label",
|
||||
platform::ICON_FA_COMMENT);
|
||||
ImGui::SetNextItemWidth(combo_w);
|
||||
if (ImGui::BeginCombo(label_text, mjLABELSTRING[vis_options_.label])) {
|
||||
for (int n = 0; n < mjNLABEL; n++) {
|
||||
if (ImGui::Selectable(mjLABELSTRING[n], (vis_options_.label == n))) {
|
||||
vis_options_.label = n;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
// Frame selector.
|
||||
{
|
||||
char frame_text[32];
|
||||
std::snprintf(frame_text, sizeof(frame_text), "%s Frame",
|
||||
platform::ICON_FA_ARROWS);
|
||||
ImGui::SetNextItemWidth(combo_w);
|
||||
if (ImGui::BeginCombo(frame_text, mjFRAMESTRING[vis_options_.frame])) {
|
||||
for (int n = 0; n < mjNFRAME; n++) {
|
||||
if (ImGui::Selectable(mjFRAMESTRING[n], (vis_options_.frame == n))) {
|
||||
vis_options_.frame = n;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
}
|
||||
|
||||
// Copy camera button.
|
||||
{
|
||||
char copy_cam_label[48];
|
||||
std::snprintf(copy_cam_label, sizeof(copy_cam_label), "%s Copy Camera",
|
||||
platform::ICON_FA_COPY);
|
||||
if (ImGui::Button(copy_cam_label)) {
|
||||
std::string camera_string =
|
||||
platform::CameraToString(data(), &camera_);
|
||||
platform::MaybeSaveToClipboard(camera_string);
|
||||
}
|
||||
ImGui::SetItemTooltip("%s",
|
||||
"Copy the current camera pose as an MJCF XML string");
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Separator();
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::PopID();
|
||||
|
||||
platform::RenderingGui(model(), &vis_options_, renderer_->GetRenderFlags(),
|
||||
min_width);
|
||||
ImGui::TreePop();
|
||||
@@ -1126,7 +1440,6 @@ void App::DataInspectorGui() {
|
||||
|
||||
ImGui::BeginChild("ControlsGui", {0, 0}, child_flags);
|
||||
if (platform::SectionHeader("Controls", node_flags, 0.65f)) {
|
||||
|
||||
float noise_scale = 0;
|
||||
float noise_rate = 0;
|
||||
step_control_.GetNoiseParameters(noise_scale, noise_rate);
|
||||
@@ -1477,8 +1790,7 @@ void App::ToolBarGui() {
|
||||
const float copy_btn_width = ImGui::GetFrameHeight();
|
||||
const float sp = ImGui::GetStyle().ItemSpacing.x;
|
||||
const float right_width = copy_btn_width + label_width + sp +
|
||||
label_width + sp + label_width + sp +
|
||||
copy_btn_width;
|
||||
label_width + sp + label_width;
|
||||
const float separator_width = ImGui::GetFrameHeight() * .6f;
|
||||
|
||||
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
|
||||
@@ -1529,11 +1841,6 @@ void App::ToolBarGui() {
|
||||
ImGui::SameLine();
|
||||
platform::FrameSelectionGui(&vis_options_);
|
||||
|
||||
ImGui::SameLine();
|
||||
if (platform::ThemeSelectGui(&ui_.theme, square_size)) {
|
||||
platform::SetupTheme(ui_.theme);
|
||||
ImGui::GetIO().WantSaveIniSettings = true;
|
||||
}
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
@@ -1541,10 +1848,7 @@ void App::ToolBarGui() {
|
||||
}
|
||||
|
||||
void App::StatusBarGui() {
|
||||
if (ImGui::BeginTable("##StatusBarTable", 2)) {
|
||||
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch);
|
||||
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 520);
|
||||
|
||||
if (ImGui::BeginTable("##StatusBarTable", 1)) {
|
||||
ImGui::TableNextColumn();
|
||||
|
||||
if (!has_model()) {
|
||||
@@ -1569,46 +1873,6 @@ void App::StatusBarGui() {
|
||||
ImGui::Text(" | Edit Error: %s", edit_error_.c_str());
|
||||
}
|
||||
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::Text("%s", " |");
|
||||
|
||||
// Frame scrubber.
|
||||
platform::ScopedStyle style;
|
||||
|
||||
style.Var(ImGuiStyleVar_FrameBorderSize, 0);
|
||||
style.Color(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_WindowBg]);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_PREV_FRAME)) {
|
||||
LoadHistory(sim_history_.GetIndex() - 1);
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Previous Frame");
|
||||
|
||||
style.Reset();
|
||||
ImGui::SameLine();
|
||||
ImGui::SetNextItemWidth(450);
|
||||
int index = sim_history_.GetIndex();
|
||||
if (ImGui::SliderInt("##ScrubIndex", &index, 1 - sim_history_.Size(), 0)) {
|
||||
LoadHistory(index);
|
||||
}
|
||||
|
||||
style.Var(ImGuiStyleVar_FrameBorderSize, 0);
|
||||
style.Color(ImGuiCol_Button, ImGui::GetStyle().Colors[ImGuiCol_WindowBg]);
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_NEXT_FRAME)) {
|
||||
if (sim_history_.GetIndex() == 0) {
|
||||
step_control_.RequestSingleStep();
|
||||
} else {
|
||||
LoadHistory(sim_history_.GetIndex() + 1);
|
||||
}
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Next Frame");
|
||||
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button(ICON_CURR_FRAME)) {
|
||||
LoadHistory(0);
|
||||
}
|
||||
ImGui::SetItemTooltip("%s", "Current Frame");
|
||||
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
@@ -1707,6 +1971,14 @@ void App::MainMenuGui() {
|
||||
"Shift+Tab")) {
|
||||
tmp_.inspector_panel = !tmp_.inspector_panel;
|
||||
}
|
||||
if (ImGui::MenuItem(
|
||||
tmp_.toolbar ? "Hide Toolbar" : "Show Toolbar")) {
|
||||
tmp_.toolbar = !tmp_.toolbar;
|
||||
}
|
||||
if (ImGui::MenuItem(
|
||||
tmp_.status_bar ? "Hide Status Bar" : "Show Status Bar")) {
|
||||
tmp_.status_bar = !tmp_.status_bar;
|
||||
}
|
||||
if (ImGui::MenuItem("Full Screen", "F11")) {
|
||||
tmp_.full_screen = !tmp_.full_screen;
|
||||
}
|
||||
@@ -1723,6 +1995,29 @@ void App::MainMenuGui() {
|
||||
if (ImGui::MenuItem("Picture-in-Picture")) {
|
||||
tmp_.picture_in_picture = !tmp_.picture_in_picture;
|
||||
}
|
||||
ImGui::Separator();
|
||||
|
||||
if (ImGui::BeginMenu("Theme")) {
|
||||
if (ImGui::MenuItem("Light", nullptr,
|
||||
ui_.theme == platform::GuiTheme::kLight)) {
|
||||
ui_.theme = platform::GuiTheme::kLight;
|
||||
platform::SetupTheme(ui_.theme);
|
||||
ImGui::GetIO().WantSaveIniSettings = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Dark", nullptr,
|
||||
ui_.theme == platform::GuiTheme::kDark)) {
|
||||
ui_.theme = platform::GuiTheme::kDark;
|
||||
platform::SetupTheme(ui_.theme);
|
||||
ImGui::GetIO().WantSaveIniSettings = true;
|
||||
}
|
||||
if (ImGui::MenuItem("Classic", nullptr,
|
||||
ui_.theme == platform::GuiTheme::kClassic)) {
|
||||
ui_.theme = platform::GuiTheme::kClassic;
|
||||
platform::SetupTheme(ui_.theme);
|
||||
ImGui::GetIO().WantSaveIniSettings = true;
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
if (ImGui::BeginMenu("Graphics Mode (Experimental)")) {
|
||||
|
||||
@@ -134,6 +134,8 @@ class App {
|
||||
bool profiler = false;
|
||||
bool picture_in_picture = false;
|
||||
bool options_panel = true;
|
||||
bool toolbar = false;
|
||||
bool status_bar = false;
|
||||
bool inspector_panel = true;
|
||||
bool full_screen = false;
|
||||
bool style_editor = false;
|
||||
|
||||
Reference in New Issue
Block a user