mirror of
https://github.com/leozide/leocad.git
synced 2026-10-26 22:10:32 +00:00
Preserve ancestor steps while editing nested submodels
Drilling into a child deactivated its parent and evaluated the parent at its final step. After navigating to an earlier step, this moved surrounding geometry and separated the child's editing transform from its placement. Keep the complete editing path active at its chosen steps, and use that path when filtering ancestor geometry for rendering. Rebuild the transform from the selected instances when restoring a tab so changes in an ancestor's own tab also keep the editing target aligned. Returning through a breadcrumb deactivates only departed descendants; ending editing restores completed assembly poses while retaining stored step choices. Also route Submodel Properties to the model currently being edited rather than the tab model. Validated the macOS Qt 6 application build, all 8 Qt Test cases, and 106 focused compiled-application checks covering ancestor poses and visibility, properties edits, tab switching, breadcrumbs, focus status, and exports.
This commit is contained in:
1 parent
688e2f70f1
commit
3db4b8e70b
7 files changed
+48
-36
No files matched your search
@@ -3611,7 +3611,8 @@ void lcMainWindow::HandleCommand(lcCommandId CommandId)
|
||||
break;
|
||||
|
||||
case LC_MODEL_PROPERTIES:
|
||||
lcGetActiveModel()->ShowPropertiesDialog();
|
||||
if (ActiveModel)
|
||||
ActiveModel->ShowPropertiesDialog();
|
||||
break;
|
||||
|
||||
case LC_MODEL_LIST:
|
||||
|
||||
+3
-1
@@ -1660,9 +1660,11 @@ void lcModel::GetScene(lcScene* Scene, const lcCamera* ViewCamera, bool AllowHig
|
||||
|
||||
void lcModel::AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const
|
||||
{
|
||||
const bool Editing = ParentActive || Scene->IsModelEditing(this);
|
||||
|
||||
for (const std::unique_ptr<lcPiece>& Piece : mPieces)
|
||||
{
|
||||
const bool Visible = ParentActive ? (Piece->IsSelected() || Piece->IsVisible(mCurrentStep)) : Piece->IsVisibleInSubModel();
|
||||
const bool Visible = Editing ? (Piece->IsSelected() || Piece->IsVisible(mCurrentStep)) : Piece->IsVisibleInSubModel();
|
||||
|
||||
if (Visible)
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ void lcScene::Begin(const lcMatrix44& ViewMatrix)
|
||||
mHighlightRenderMode = lcHighlightRenderMode::Tint;
|
||||
mViewMatrix = ViewMatrix;
|
||||
mActiveSubmodelInstance = nullptr;
|
||||
mModelEditingPath.clear();
|
||||
mRenderMeshes.clear();
|
||||
mOpaqueMeshes.clear();
|
||||
mTranslucentMeshes.clear();
|
||||
|
||||
+8
-1
@@ -35,10 +35,16 @@ class lcScene
|
||||
public:
|
||||
lcScene();
|
||||
|
||||
void SetActiveSubmodelInstance(lcPiece* ActiveSubmodelInstance, const lcMatrix44& ActiveSubmodelTransform)
|
||||
void SetActiveSubmodelInstance(lcPiece* ActiveSubmodelInstance, const lcMatrix44& ActiveSubmodelTransform, const std::vector<lcModel*>& ModelEditingPath)
|
||||
{
|
||||
mActiveSubmodelInstance = ActiveSubmodelInstance;
|
||||
mActiveSubmodelTransform = ActiveSubmodelTransform;
|
||||
mModelEditingPath = ModelEditingPath;
|
||||
}
|
||||
|
||||
bool IsModelEditing(const lcModel* Model) const
|
||||
{
|
||||
return mDrawInterface && mActiveSubmodelInstance && std::find(mModelEditingPath.begin(), mModelEditingPath.end(), Model) != mModelEditingPath.end();
|
||||
}
|
||||
|
||||
lcPiece* GetActiveSubmodelInstance() const
|
||||
@@ -165,6 +171,7 @@ protected:
|
||||
lcMatrix44 mViewMatrix;
|
||||
lcMatrix44 mActiveSubmodelTransform;
|
||||
lcPiece* mActiveSubmodelInstance = nullptr;
|
||||
std::vector<lcModel*> mModelEditingPath;
|
||||
lcShadingMode mShadingMode;
|
||||
bool mDrawInterface = false;
|
||||
lcHighlightRenderMode mHighlightRenderMode;
|
||||
|
||||
+26
-27
@@ -152,12 +152,24 @@ std::vector<lcModel*> lcView::GetModelEditingPath() const
|
||||
{
|
||||
std::vector<lcModel*> Models = { mModel };
|
||||
|
||||
for (const std::pair<lcPiece*, lcMatrix44>& Entry : mSubmodelEditingPath)
|
||||
Models.push_back(Entry.first->mPieceData->GetModel());
|
||||
for (const lcPiece* Piece : mSubmodelEditingPath)
|
||||
Models.push_back(Piece->mPieceData->GetModel());
|
||||
|
||||
return Models;
|
||||
}
|
||||
|
||||
void lcView::RestoreModelEditingContext()
|
||||
{
|
||||
mModel->SetActive(true);
|
||||
mActiveSubmodelTransform = lcMatrix44Identity();
|
||||
|
||||
for (lcPiece* Piece : mSubmodelEditingPath)
|
||||
{
|
||||
mActiveSubmodelTransform = lcMul(Piece->mModelWorld, mActiveSubmodelTransform);
|
||||
Piece->mPieceData->GetModel()->SetActive(true);
|
||||
}
|
||||
}
|
||||
|
||||
void lcView::SetSubmodelActive(size_t Depth)
|
||||
{
|
||||
if (Depth > mSubmodelEditingPath.size())
|
||||
@@ -165,26 +177,22 @@ void lcView::SetSubmodelActive(size_t Depth)
|
||||
|
||||
StopTracking(true);
|
||||
|
||||
lcModel* ActiveModel = GetActiveModel();
|
||||
const std::vector<lcModel*> EditingModels = GetModelEditingPath();
|
||||
|
||||
if (mActiveSubmodelInstance)
|
||||
{
|
||||
ActiveModel->SetActive(false);
|
||||
for (size_t Index = EditingModels.size(); Index > Depth + 1; Index--)
|
||||
EditingModels[Index - 1]->SetActive(false);
|
||||
|
||||
std::vector<lcModel*> UpdatedModels;
|
||||
ActiveModel->UpdatePieceData(UpdatedModels);
|
||||
}
|
||||
std::vector<lcModel*> UpdatedModels;
|
||||
for (size_t Index = EditingModels.size(); Index > Depth + 1; Index--)
|
||||
EditingModels[Index - 1]->UpdatePieceData(UpdatedModels);
|
||||
|
||||
mSubmodelEditingPath.resize(Depth);
|
||||
mActiveSubmodelInstance = nullptr;
|
||||
|
||||
if (!mSubmodelEditingPath.empty())
|
||||
{
|
||||
mActiveSubmodelInstance = mSubmodelEditingPath.back().first;
|
||||
mActiveSubmodelTransform = mSubmodelEditingPath.back().second;
|
||||
}
|
||||
mActiveSubmodelInstance = mSubmodelEditingPath.back();
|
||||
|
||||
GetActiveModel()->SetActive(true);
|
||||
RestoreModelEditingContext();
|
||||
GetActiveModel()->UpdateInterface();
|
||||
}
|
||||
|
||||
@@ -206,22 +214,13 @@ void lcView::SetSelectedSubmodelActive()
|
||||
if (!Piece->mPieceData->IsModel())
|
||||
return;
|
||||
|
||||
// Preserve the selected instance path and capture its transform before SetActive(false) changes the step.
|
||||
lcMatrix44 SubmodelTransform = Piece->mModelWorld;
|
||||
|
||||
if (mActiveSubmodelInstance)
|
||||
SubmodelTransform = lcMul(SubmodelTransform, mActiveSubmodelTransform);
|
||||
|
||||
if (mActiveSubmodelInstance)
|
||||
ActiveModel->SetActive(false);
|
||||
|
||||
mSubmodelEditingPath.emplace_back(Piece, SubmodelTransform);
|
||||
mActiveSubmodelTransform = SubmodelTransform;
|
||||
// Keep ancestor models at their chosen steps so the selected instance stays in place.
|
||||
mSubmodelEditingPath.push_back(Piece);
|
||||
mActiveSubmodelInstance = Piece;
|
||||
|
||||
ActiveModel = mActiveSubmodelInstance->mPieceData->GetModel();
|
||||
ActiveModel->SetTemporaryStep(ActiveModel->GetLastStep());
|
||||
ActiveModel->SetActive(true);
|
||||
RestoreModelEditingContext();
|
||||
|
||||
RemoveCamera();
|
||||
|
||||
@@ -1048,7 +1047,7 @@ void lcView::OnDraw()
|
||||
|
||||
mScene->Begin(mCamera->mWorldView);
|
||||
|
||||
mScene->SetActiveSubmodelInstance(mActiveSubmodelInstance, mActiveSubmodelTransform);
|
||||
mScene->SetActiveSubmodelInstance(mActiveSubmodelInstance, mActiveSubmodelTransform, GetModelEditingPath());
|
||||
mScene->SetDrawInterface(DrawInterface);
|
||||
|
||||
bool DrawInsertPreview = DrawInterface && std::any_of(mViews.begin(), mViews.end(), [](lcView* View){ return View->mTrackTool == lcTrackTool::Insert; });
|
||||
|
||||
+2
-1
@@ -236,6 +236,7 @@ public:
|
||||
|
||||
lcModel* GetActiveModel() const;
|
||||
std::vector<lcModel*> GetModelEditingPath() const;
|
||||
void RestoreModelEditingContext();
|
||||
void SetSubmodelActive(size_t Depth);
|
||||
void SetTopSubmodelActive();
|
||||
void SetSelectedSubmodelActive();
|
||||
@@ -395,7 +396,7 @@ protected:
|
||||
lcModel* mModel = nullptr;
|
||||
lcPiece* mActiveSubmodelInstance = nullptr;
|
||||
lcMatrix44 mActiveSubmodelTransform;
|
||||
std::vector<std::pair<lcPiece*, lcMatrix44>> mSubmodelEditingPath;
|
||||
std::vector<lcPiece*> mSubmodelEditingPath;
|
||||
|
||||
lcCamera* mCamera = nullptr;
|
||||
|
||||
|
||||
+6
-5
@@ -234,12 +234,13 @@ void Project::SetActiveModel(lcModel* ActiveModel, bool UpdateInterface)
|
||||
{
|
||||
gMainWindow->SetCurrentModelTab(mActiveModel, true);
|
||||
|
||||
// The tab may still be editing a nested submodel at its current step.
|
||||
lcModel* EditingModel = gMainWindow->GetActiveModel();
|
||||
if (EditingModel)
|
||||
// Restore the current steps of the editing target and its surrounding ancestors.
|
||||
lcView* EditingView = gMainWindow->GetActiveView();
|
||||
|
||||
if (EditingView)
|
||||
{
|
||||
EditingModel->SetActive(true);
|
||||
EditingModel->UpdateInterface();
|
||||
EditingView->RestoreModelEditingContext();
|
||||
EditingView->GetActiveModel()->UpdateInterface();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user