Disable spec editor when no spec is available.

PiperOrigin-RevId: 942493527
Change-Id: I90e1a0049b9cc9a82a5ede3a4a74a41425d5bee3
This commit is contained in:
Haroon Qureshi
2026-07-04 07:28:34 -07:00
committed by Copybara-Service
parent 38f0ff3caa
commit c665f0b59e
3 changed files with 50 additions and 2 deletions
@@ -24,6 +24,11 @@ namespace mujoco::platform {
SpecEditor::SpecEditor(int history_size) : capacity_(history_size) {}
void SpecEditor::Reset() {
ref_spec_.reset();
active_spec_.reset();
}
void SpecEditor::Reset(const mjSpec& spec) {
active_element_key_ = kInvalidElementKey;
active_element_ = nullptr;
@@ -55,6 +60,10 @@ void SpecEditor::Reset(const mjSpec& spec) {
}
std::unique_ptr<ModelHolder> SpecEditor::Compile() {
if (!active_spec_) {
return nullptr;
}
auto holder = ModelHolder::FromSpec(mj_copySpec(active_spec_.get()));
if (holder->ok()) {
ref_spec_ = Copy(active_spec_.get());
@@ -66,6 +75,10 @@ std::unique_ptr<ModelHolder> SpecEditor::Compile() {
mjSpec* SpecEditor::GetActiveSpec() const { return active_spec_.get(); }
mjsElement* SpecEditor::AddElement(mjtObj type) {
if (!active_spec_) {
return nullptr;
}
// TODO: check that type is only for spec elements.
mjsElement* element = AddElementToSpec(active_spec_.get(), type);
if (element) {
@@ -82,6 +95,10 @@ mjsElement* SpecEditor::AddElement(mjtObj type) {
}
mjsElement* SpecEditor::AddBodyElement(mjsBody* body, mjtObj type) {
if (!active_spec_) {
return nullptr;
}
// TODO: check that type is only for body elements.
mjsElement* element = AddElementToSpec(active_spec_.get(), type, body);
if (element) {
@@ -98,6 +115,10 @@ mjsElement* SpecEditor::AddBodyElement(mjsBody* body, mjtObj type) {
}
void SpecEditor::DeleteActiveElement() {
if (!active_spec_) {
return;
}
if (active_element_) {
const mjtObj type = active_element_->elemtype;
const int index = active_map_.Remove(active_element_key_);
@@ -116,6 +137,10 @@ void SpecEditor::DeleteActiveElement() {
}
void SpecEditor::SetActiveElement(mjsElement* element) {
if (!active_spec_) {
return;
}
if (element == nullptr) {
ref_element_ = nullptr;
active_element_ = nullptr;
@@ -152,6 +177,10 @@ void SpecEditor::SetActiveElement(mjsElement* element) {
}
void SpecEditor::UpdateReferenceElement() {
if (!active_spec_) {
return;
}
if (active_element_ == nullptr) {
ref_element_ = nullptr;
} else {
@@ -175,6 +204,10 @@ mjsElement* SpecEditor::GetActiveElement() const { return active_element_; }
mjsElement* SpecEditor::GetRefElement() const { return ref_element_; }
void SpecEditor::CommitChanges(mjsElement* element) {
if (!active_spec_) {
return;
}
if (element == nullptr) {
mju_warning("Element is null.");
return;
@@ -233,6 +266,10 @@ void SpecEditor::Redo() {
bool SpecEditor::CanRedo() const { return cursor_ < history_.size() - 1; }
void SpecEditor::AppendHistory(HistoryEntry entry) {
if (!active_spec_) {
return;
}
++cursor_;
while (history_.size() > cursor_) {
history_.pop_back();
@@ -38,6 +38,9 @@ class SpecEditor {
public:
explicit SpecEditor(int history_size = 256);
// Resets the editor with an empty spec. No editing will be allowed.
void Reset();
// Resets the editor to manage the given spec, clearing all cached data.
// Assumes the given spec is correctly formed (i.e. compilable).
void Reset(const mjSpec& spec);
+10 -2
View File
@@ -161,7 +161,11 @@ void App::LoadModelFromFile(const std::string& filepath) {
model_holder_ = platform::ModelHolder::FromFile(resolved_file);
if (model_holder_->ok()) {
OnModelLoaded(filepath, kModelFromFile);
spec_editor_.Reset(*spec());
if (spec()) {
spec_editor_.Reset(*spec());
} else {
spec_editor_.Reset();
}
UpdateFilePaths(resolved_file);
if (model() && model()->names) {
// Assumes the first string in the model is the name of the model itself.
@@ -188,7 +192,11 @@ void App::LoadModelFromBuffer(std::span<const std::byte> buffer,
} else {
SetLoadError(std::string(model_holder_->error()));
}
spec_editor_.Reset(*spec());
if (spec()) {
spec_editor_.Reset(*spec());
} else {
spec_editor_.Reset();
}
}
void App::OnModelLoaded(std::string filename, ModelKind model_kind) {