UI improvements. Fixes #1274.
Copybara import of the project: -- a1297d997d0b3cc624bbd1e704ffb7fbb2c5db9d by Emo Todorov <etodorov@gmail.com>: UI imrovements When OpenGL buffer size is too small to hold entire UI with all sections open, older sections (as determined by latest mouse click) are automatically closed as needed. To test this new functionality, uncomment the test near the top of mjui_resize(). UI items now have userid, which can be used for event handling. It is set through the (new) last field of mjuiDef, called otherint. Sections titles can now have a checkmark - in which case they are rendered differently. Set via mjuiDef.otherint: 0- none (as before), 1- rendering changed but box not shown, 2- box shown. This can be used to label sections of special interest to the application. -- b0405bfb3005586ef1d2656ea9cc43c608225927 by Emo Todorov <etodorov@gmail.com>: more ui improvements Implemented mjPRESERVE state for adding sections and separators, so you don't have to keep track of old states. simulate.cc is now modified to use this new functionality. I also made the separators in the Physics section collapsible. If you don't like it, change them back to state 1. Also added functionality for handling section checkboxes. -- 10f4c49be62a6605a38b7c0c7bfae1629024ba31 by Emo Todorov <etodorov@gmail.com>: even more ui improvements Selection boxes that extend below the current UI height are finally rendered in full. Sections and collapsible separators now have rounded corners. The radius can be controlled from theme spacing. More theme color settings were added. In particular, color gradients can now be disabled (the two end colors are set independently). -- 96c2dc601a25d31c93b21f8e089d349e729e829e by Emo Todorov <etodorov@gmail.com>: final ui improvements Cleaned up the code a bit. Added more control for color gradients. -- c9eddb679f36df3f0745d37e3fa90c4e66ee6b98 by Emo Todorov <etodorov@gmail.com>: bug fix Fixed some rendering bugs in the new functionality. COPYBARA_INTEGRATE_REVIEW=https://github.com/google-deepmind/mujoco/pull/1749 from emotodorov:ui_improve ddfc21dbcf0482b8f0d5eacab21847c302f71440 PiperOrigin-RevId: 646060325 Change-Id: Idb27aae7cd0311d00f26387bcadf5891175e867d
This commit is contained in:
committed by
Copybara-Service
parent
e66b9a36b2
commit
ee6a1dba28
+53
-55
@@ -117,13 +117,13 @@ enum {
|
||||
|
||||
// file section of UI
|
||||
const mjuiDef defFile[] = {
|
||||
{mjITEM_SECTION, "File", 1, nullptr, "AF"},
|
||||
{mjITEM_BUTTON, "Save xml", 2, nullptr, ""},
|
||||
{mjITEM_BUTTON, "Save mjb", 2, nullptr, ""},
|
||||
{mjITEM_BUTTON, "Print model", 2, nullptr, "CM"},
|
||||
{mjITEM_BUTTON, "Print data", 2, nullptr, "CD"},
|
||||
{mjITEM_BUTTON, "Quit", 1, nullptr, "CQ"},
|
||||
{mjITEM_BUTTON, "Screenshot", 2, nullptr, "CP"},
|
||||
{mjITEM_SECTION, "File", mjPRESERVE, nullptr, "AF"},
|
||||
{mjITEM_BUTTON, "Save xml", 2, nullptr, ""},
|
||||
{mjITEM_BUTTON, "Save mjb", 2, nullptr, ""},
|
||||
{mjITEM_BUTTON, "Print model", 2, nullptr, "CM"},
|
||||
{mjITEM_BUTTON, "Print data", 2, nullptr, "CD"},
|
||||
{mjITEM_BUTTON, "Quit", 1, nullptr, "CQ"},
|
||||
{mjITEM_BUTTON, "Screenshot", 2, nullptr, "CP"},
|
||||
{mjITEM_END}
|
||||
};
|
||||
|
||||
@@ -674,15 +674,15 @@ void UpdateWatch(mj::Simulate* sim, const mjModel* m, const mjData* d) {
|
||||
//---------------------------------- UI construction -----------------------------------------------
|
||||
|
||||
// make physics section of UI
|
||||
void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
|
||||
void MakePhysicsSection(mj::Simulate* sim) {
|
||||
mjOption* opt = sim->is_passive_ ? &sim->scnstate_.model.opt : &sim->m_->opt;
|
||||
mjuiDef defPhysics[] = {
|
||||
{mjITEM_SECTION, "Physics", oldstate, nullptr, "AP"},
|
||||
{mjITEM_SECTION, "Physics", mjPRESERVE, nullptr, "AP"},
|
||||
{mjITEM_SELECT, "Integrator", 2, &(opt->integrator), "Euler\nRK4\nimplicit\nimplicitfast"},
|
||||
{mjITEM_SELECT, "Cone", 2, &(opt->cone), "Pyramidal\nElliptic"},
|
||||
{mjITEM_SELECT, "Jacobian", 2, &(opt->jacobian), "Dense\nSparse\nAuto"},
|
||||
{mjITEM_SELECT, "Solver", 2, &(opt->solver), "PGS\nCG\nNewton"},
|
||||
{mjITEM_SEPARATOR, "Algorithmic Parameters", 1},
|
||||
{mjITEM_SEPARATOR, "Algorithmic Parameters", mjPRESERVE},
|
||||
{mjITEM_EDITNUM, "Timestep", 2, &(opt->timestep), "1 0 1"},
|
||||
{mjITEM_EDITINT, "Iterations", 2, &(opt->iterations), "1 0 1000"},
|
||||
{mjITEM_EDITNUM, "Tolerance", 2, &(opt->tolerance), "1 0 1"},
|
||||
@@ -695,22 +695,22 @@ void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
|
||||
{mjITEM_EDITNUM, "API Rate", 2, &(opt->apirate), "1 0 1000"},
|
||||
{mjITEM_EDITINT, "SDF Iter", 2, &(opt->sdf_iterations), "1 1 20"},
|
||||
{mjITEM_EDITINT, "SDF Init", 2, &(opt->sdf_initpoints), "1 1 100"},
|
||||
{mjITEM_SEPARATOR, "Physical Parameters", 1},
|
||||
{mjITEM_SEPARATOR, "Physical Parameters", mjPRESERVE},
|
||||
{mjITEM_EDITNUM, "Gravity", 2, opt->gravity, "3"},
|
||||
{mjITEM_EDITNUM, "Wind", 2, opt->wind, "3"},
|
||||
{mjITEM_EDITNUM, "Magnetic", 2, opt->magnetic, "3"},
|
||||
{mjITEM_EDITNUM, "Density", 2, &(opt->density), "1"},
|
||||
{mjITEM_EDITNUM, "Viscosity", 2, &(opt->viscosity), "1"},
|
||||
{mjITEM_EDITNUM, "Imp Ratio", 2, &(opt->impratio), "1"},
|
||||
{mjITEM_SEPARATOR, "Disable Flags", 1},
|
||||
{mjITEM_SEPARATOR, "Disable Flags", mjPRESERVE},
|
||||
{mjITEM_END}
|
||||
};
|
||||
mjuiDef defEnableFlags[] = {
|
||||
{mjITEM_SEPARATOR, "Enable Flags", 1},
|
||||
{mjITEM_SEPARATOR, "Enable Flags", mjPRESERVE},
|
||||
{mjITEM_END}
|
||||
};
|
||||
mjuiDef defOverride[] = {
|
||||
{mjITEM_SEPARATOR, "Contact Override", 1},
|
||||
{mjITEM_SEPARATOR, "Contact Override", mjPRESERVE},
|
||||
{mjITEM_EDITNUM, "Margin", 2, &(opt->o_margin), "1"},
|
||||
{mjITEM_EDITNUM, "Sol Imp", 2, &(opt->o_solimp), "5"},
|
||||
{mjITEM_EDITNUM, "Sol Ref", 2, &(opt->o_solref), "2"},
|
||||
@@ -718,7 +718,7 @@ void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
|
||||
{mjITEM_END}
|
||||
};
|
||||
mjuiDef defDisableActuator[] = {
|
||||
{mjITEM_SEPARATOR, "Actuator Group Enable", 1},
|
||||
{mjITEM_SEPARATOR, "Actuator Group Enable", mjPRESERVE},
|
||||
{mjITEM_CHECKBYTE, "Act Group 0", 2, sim->enableactuator+0, ""},
|
||||
{mjITEM_CHECKBYTE, "Act Group 1", 2, sim->enableactuator+1, ""},
|
||||
{mjITEM_CHECKBYTE, "Act Group 2", 2, sim->enableactuator+2, ""},
|
||||
@@ -757,12 +757,12 @@ void MakePhysicsSection(mj::Simulate* sim, int oldstate) {
|
||||
|
||||
|
||||
// make rendering section of UI
|
||||
void MakeRenderingSection(mj::Simulate* sim, const mjModel* m, int oldstate) {
|
||||
void MakeRenderingSection(mj::Simulate* sim, const mjModel* m) {
|
||||
mjuiDef defRendering[] = {
|
||||
{
|
||||
mjITEM_SECTION,
|
||||
"Rendering",
|
||||
oldstate,
|
||||
mjPRESERVE,
|
||||
nullptr,
|
||||
"AR"
|
||||
},
|
||||
@@ -876,18 +876,18 @@ void MakeRenderingSection(mj::Simulate* sim, const mjModel* m, int oldstate) {
|
||||
}
|
||||
|
||||
// make visualization section of UI
|
||||
void MakeVisualizationSection(mj::Simulate* sim, const mjModel* m, int oldstate) {
|
||||
void MakeVisualizationSection(mj::Simulate* sim, const mjModel* m) {
|
||||
mjStatistic* stat = sim->is_passive_ ? &sim->scnstate_.model.stat : &sim->m_->stat;
|
||||
mjVisual* vis = sim->is_passive_ ? &sim->scnstate_.model.vis : &sim->m_->vis;
|
||||
|
||||
mjuiDef defVisualization[] = {
|
||||
{mjITEM_SECTION, "Visualization", oldstate, nullptr, "AV"},
|
||||
{mjITEM_SECTION, "Visualization", mjPRESERVE, nullptr, "AV"},
|
||||
{mjITEM_SEPARATOR, "Headlight", 1},
|
||||
{mjITEM_RADIO, "Active", 5, &(vis->headlight.active), "Off\nOn"},
|
||||
{mjITEM_EDITFLOAT, "Ambient", 2, &(vis->headlight.ambient), "3"},
|
||||
{mjITEM_EDITFLOAT, "Diffuse", 2, &(vis->headlight.diffuse), "3"},
|
||||
{mjITEM_EDITFLOAT, "Specular", 2, &(vis->headlight.specular), "3"},
|
||||
{mjITEM_SEPARATOR, "Free Camera", 1},
|
||||
{mjITEM_SEPARATOR, "Free Camera", 1},
|
||||
{mjITEM_RADIO, "Orthographic", 2, &(vis->global.orthographic), "No\nYes"},
|
||||
{mjITEM_EDITFLOAT, "Field of view", 2, &(vis->global.fovy), "1"},
|
||||
{mjITEM_EDITNUM, "Center", 2, &(stat->center), "3"},
|
||||
@@ -937,9 +937,9 @@ void MakeVisualizationSection(mj::Simulate* sim, const mjModel* m, int oldstate)
|
||||
}
|
||||
|
||||
// make group section of UI
|
||||
void MakeGroupSection(mj::Simulate* sim, int oldstate) {
|
||||
void MakeGroupSection(mj::Simulate* sim) {
|
||||
mjuiDef defGroup[] = {
|
||||
{mjITEM_SECTION, "Group enable", oldstate, nullptr, "AG"},
|
||||
{mjITEM_SECTION, "Group enable", mjPRESERVE, nullptr, "AG"},
|
||||
{mjITEM_SEPARATOR, "Geom groups", 1},
|
||||
{mjITEM_CHECKBYTE, "Geom 0", 2, sim->opt.geomgroup, " 0"},
|
||||
{mjITEM_CHECKBYTE, "Geom 1", 2, sim->opt.geomgroup+1, " 1"},
|
||||
@@ -997,9 +997,9 @@ void MakeGroupSection(mj::Simulate* sim, int oldstate) {
|
||||
}
|
||||
|
||||
// make joint section of UI
|
||||
void MakeJointSection(mj::Simulate* sim, int oldstate) {
|
||||
void MakeJointSection(mj::Simulate* sim) {
|
||||
mjuiDef defJoint[] = {
|
||||
{mjITEM_SECTION, "Joint", oldstate, nullptr, "AJ"},
|
||||
{mjITEM_SECTION, "Joint", mjPRESERVE, nullptr, "AJ"},
|
||||
{mjITEM_END}
|
||||
};
|
||||
mjuiDef defSlider[] = {
|
||||
@@ -1050,9 +1050,9 @@ void MakeJointSection(mj::Simulate* sim, int oldstate) {
|
||||
}
|
||||
|
||||
// make control section of UI
|
||||
void MakeControlSection(mj::Simulate* sim, int oldstate) {
|
||||
void MakeControlSection(mj::Simulate* sim) {
|
||||
mjuiDef defControl[] = {
|
||||
{mjITEM_SECTION, "Control", oldstate, nullptr, "AC"},
|
||||
{mjITEM_SECTION, "Control", mjPRESERVE, nullptr, "AC"},
|
||||
{mjITEM_BUTTON, "Clear all", 2},
|
||||
{mjITEM_END}
|
||||
};
|
||||
@@ -1107,35 +1107,17 @@ void MakeControlSection(mj::Simulate* sim, int oldstate) {
|
||||
|
||||
// make model-dependent UI sections
|
||||
void MakeUiSections(mj::Simulate* sim, const mjModel* m, const mjData* d) {
|
||||
// get section open-close state, UI 0
|
||||
int oldstate0[NSECT0];
|
||||
for (int i=0; i<NSECT0; i++) {
|
||||
oldstate0[i] = 0;
|
||||
if (sim->ui0.nsect>i) {
|
||||
oldstate0[i] = sim->ui0.sect[i].state;
|
||||
}
|
||||
}
|
||||
|
||||
// get section open-close state, UI 1
|
||||
int oldstate1[NSECT1];
|
||||
for (int i=0; i<NSECT1; i++) {
|
||||
oldstate1[i] = 0;
|
||||
if (sim->ui1.nsect>i) {
|
||||
oldstate1[i] = sim->ui1.sect[i].state;
|
||||
}
|
||||
}
|
||||
|
||||
// clear model-dependent sections of UI
|
||||
sim->ui0.nsect = SECT_PHYSICS;
|
||||
sim->ui1.nsect = 0;
|
||||
|
||||
// make
|
||||
MakePhysicsSection(sim, oldstate0[SECT_PHYSICS]);
|
||||
MakeRenderingSection(sim, m, oldstate0[SECT_RENDERING]);
|
||||
MakeVisualizationSection(sim, m, oldstate0[SECT_VISUALIZATION]);
|
||||
MakeGroupSection(sim, oldstate0[SECT_GROUP]);
|
||||
MakeJointSection(sim, oldstate1[SECT_JOINT]);
|
||||
MakeControlSection(sim, oldstate1[SECT_CONTROL]);
|
||||
MakePhysicsSection(sim);
|
||||
MakeRenderingSection(sim, m);
|
||||
MakeVisualizationSection(sim, m);
|
||||
MakeGroupSection(sim);
|
||||
MakeJointSection(sim);
|
||||
MakeControlSection(sim);
|
||||
}
|
||||
|
||||
//---------------------------------- utility functions ---------------------------------------------
|
||||
@@ -1265,7 +1247,7 @@ int ComputeFontScale(const mj::PlatformUIAdapter& platform_ui) {
|
||||
fs = 150;
|
||||
}
|
||||
fs = mju_round(fs * 0.02) * 50;
|
||||
fs = mjMIN(250, mjMAX(100, fs));
|
||||
fs = mjMIN(300, mjMAX(100, fs));
|
||||
|
||||
return fs;
|
||||
}
|
||||
@@ -1322,9 +1304,22 @@ void UiLayout(mjuiState* state) {
|
||||
rect[3].height = rect[0].height;
|
||||
}
|
||||
|
||||
// modify UI
|
||||
void UiModify(mjUI* ui, mjuiState* state, mjrContext* con) {
|
||||
mjui_resize(ui, con);
|
||||
mjr_addAux(ui->auxid, ui->width, ui->maxheight, ui->spacing.samples, con);
|
||||
|
||||
// remake aux buffer only if missing or different
|
||||
int id = ui->auxid;
|
||||
if (con->auxFBO[id] == 0 ||
|
||||
con->auxFBO_r[id] == 0 ||
|
||||
con->auxColor[id] == 0 ||
|
||||
con->auxColor_r[id] == 0 ||
|
||||
con->auxWidth[id] != ui->width ||
|
||||
con->auxHeight[id] != ui->maxheight ||
|
||||
con->auxSamples[id] != ui->spacing.samples) {
|
||||
mjr_addAux(id, ui->width, ui->maxheight, ui->spacing.samples, con);
|
||||
}
|
||||
|
||||
UiLayout(state);
|
||||
mjui_update(-1, -1, ui, state, con);
|
||||
}
|
||||
@@ -1504,7 +1499,7 @@ void UiEvent(mjuiState* state) {
|
||||
// remake joint section if joint group changed
|
||||
if (it->name[0]=='J' && it->name[1]=='o') {
|
||||
sim->ui1.nsect = SECT_JOINT;
|
||||
MakeJointSection(sim, sim->ui1.sect[SECT_JOINT].state);
|
||||
MakeJointSection(sim);
|
||||
sim->ui1.nsect = NSECT1;
|
||||
UiModify(&sim->ui1, state, &sim->platform_ui->mjr_context());
|
||||
}
|
||||
@@ -2457,7 +2452,7 @@ void Simulate::Render() {
|
||||
if (pending_.ui_remake_ctrl) {
|
||||
if (this->ui1_enable && this->ui1.sect[SECT_CONTROL].state) {
|
||||
this->ui1.nsect = SECT_CONTROL;
|
||||
MakeControlSection(this, this->ui1.sect[SECT_CONTROL].state);
|
||||
MakeControlSection(this);
|
||||
this->ui1.nsect = NSECT1;
|
||||
UiModify(&this->ui1, &this->uistate, &this->platform_ui->mjr_context());
|
||||
}
|
||||
@@ -2645,12 +2640,15 @@ void Simulate::RenderLoop() {
|
||||
this->platform_ui->SetEventCallback(UiEvent);
|
||||
this->platform_ui->SetLayoutCallback(UiLayout);
|
||||
|
||||
// populate uis with standard sections
|
||||
// populate uis with standard sections, open some sections initially
|
||||
this->ui0.userdata = this;
|
||||
this->ui1.userdata = this;
|
||||
mjui_add(&this->ui0, defFile);
|
||||
mjui_add(&this->ui0, this->def_option);
|
||||
mjui_add(&this->ui0, this->def_simulation);
|
||||
this->ui0.sect[0].state = 1;
|
||||
this->ui0.sect[1].state = 1;
|
||||
this->ui0.sect[2].state = 1;
|
||||
mjui_add(&this->ui0, this->def_watch);
|
||||
UiModify(&this->ui0, &this->uistate, &this->platform_ui->mjr_context());
|
||||
UiModify(&this->ui1, &this->uistate, &this->platform_ui->mjr_context());
|
||||
|
||||
Reference in New Issue
Block a user