mirror of
https://github.com/leozide/leocad.git
synced 2026-10-26 22:10:32 +00:00
In-place editing could use the tab model's step and focus, lose its active state after switching tabs, or resolve a nested instance through the wrong parent. Entering before the final animation key also moved geometry when drilling into a child. Use the edited model for step controls, step edits, visibility, and focus coordinates. Restore that editing target when returning to its tab, include animation keys and finite hide steps in the last step, and retain the selected instance path and transforms during nested editing. Show the editing path only during in-place edits, with links to ancestors and a close control to return to the tab model. Stack Find/Replace beneath it and preserve full names in accessible text and tooltips. Add translated source entries without changing existing translations. Add a regression test for final-key tracking through time and key edits. Validated with the macOS Qt 6 application build, all 8 Qt Test cases, and 51 focused checks against the compiled application for steps, tab switching, focus status, breadcrumbs, and Find/Replace layout. Visually checked the viewport overlay and its placement during nested editing.
325 lines
8.3 KiB
C++
325 lines
8.3 KiB
C++
#pragma once
|
|
|
|
class lcPieceData;
|
|
|
|
#include "object.h"
|
|
#include "lc_colors.h"
|
|
#include "lc_math.h"
|
|
#include "lc_assettypes.h"
|
|
|
|
#define LC_MAX_CONTROL_POINTS 1000
|
|
|
|
enum lcPieceSection : quint32
|
|
{
|
|
LC_PIECE_SECTION_INVALID = LC_OBJECT_SECTION_INVALID,
|
|
LC_PIECE_SECTION_POSITION = 0,
|
|
LC_PIECE_SECTION_CONTROL_POINT_FIRST,
|
|
LC_PIECE_SECTION_CONTROL_POINT_LAST = LC_PIECE_SECTION_CONTROL_POINT_FIRST + LC_MAX_CONTROL_POINTS - 1,
|
|
LC_PIECE_SECTION_TRAIN_TRACK_CONNECTION_FIRST = 1
|
|
};
|
|
|
|
struct lcPieceControlPoint
|
|
{
|
|
lcMatrix44 Transform;
|
|
float Scale;
|
|
|
|
bool operator==(const lcPieceControlPoint& Other) const
|
|
{
|
|
return Transform == Other.Transform && Scale == Other.Scale;
|
|
}
|
|
};
|
|
|
|
struct lcPieceHistoryState
|
|
{
|
|
lcObjectId Id;
|
|
bool Hidden;
|
|
int FileLine;
|
|
QString PieceId;
|
|
uint32_t GroupId;
|
|
int ColorIndex;
|
|
quint32 ColorCode;
|
|
lcStep StepShow;
|
|
lcStep StepHide;
|
|
lcMatrix44 PivotMatrix;
|
|
bool PivotPointValid;
|
|
std::vector<lcPieceControlPoint> ControlPoints;
|
|
lcObjectProperty<lcVector3> Position;
|
|
lcObjectProperty<lcMatrix33> Rotation;
|
|
|
|
bool operator==(const lcPieceHistoryState& Other) const
|
|
{
|
|
return Id == Other.Id && Hidden == Other.Hidden && FileLine == Other.FileLine && PieceId == Other.PieceId &&
|
|
GroupId == Other.GroupId && ColorIndex == Other.ColorIndex && ColorCode == Other.ColorCode &&
|
|
StepShow == Other.StepShow && StepHide == Other.StepHide && PivotMatrix == Other.PivotMatrix &&
|
|
PivotPointValid == Other.PivotPointValid && ControlPoints == Other.ControlPoints &&
|
|
Position == Other.Position && Rotation == Other.Rotation;
|
|
}
|
|
};
|
|
|
|
class lcPiece : public lcObject
|
|
{
|
|
public:
|
|
lcPiece();
|
|
lcPiece(lcPieceData* PieceData);
|
|
lcPiece(lcPieceDataRef PieceDataRef);
|
|
lcPiece(const lcPiece& Other);
|
|
virtual ~lcPiece();
|
|
|
|
lcPiece(lcPiece&&) = delete;
|
|
lcPiece& operator=(const lcPiece&) = delete;
|
|
lcPiece& operator=(lcPiece&&) = delete;
|
|
|
|
quint32 GetAllowedTransforms() const override;
|
|
lcVector3 GetSectionPosition(quint32 Section) const override;
|
|
|
|
void SaveLDraw(QTextStream& Stream) const;
|
|
bool ParseLDrawLine(QTextStream& Stream);
|
|
|
|
void SetFileLine(int Line)
|
|
{
|
|
mFileLine = Line;
|
|
}
|
|
|
|
int GetFileLine() const
|
|
{
|
|
return mFileLine;
|
|
}
|
|
|
|
void RayTest(lcObjectRayTest& ObjectRayTest) const override;
|
|
void BoxTest(lcObjectBoxTest& ObjectBoxTest) const override;
|
|
bool MinIntersectDist(const lcVector3& Start, const lcVector3& End, float& MinDistance, lcPieceRayTest& PieceRayTest) const;
|
|
bool IntersectsPlanes(const lcMatrix44& WorldMatrix, const lcVector4 Planes[6]) const;
|
|
void DrawInterface(lcContext* Context, const lcScene& Scene) const override;
|
|
QVariant GetPropertyValue(lcObjectPropertyId PropertyId) const override;
|
|
bool SetPropertyValue(lcObjectPropertyId PropertyId, lcStep Step, bool AddKey, QVariant Value) override;
|
|
bool HasKeyFrame(lcObjectPropertyId PropertyId, lcStep Time) const override;
|
|
lcStep GetLastStep() const override;
|
|
bool SetKeyFrame(lcObjectPropertyId PropertyId, lcStep Time, bool KeyFrame) override;
|
|
void RemoveKeyFrames() override;
|
|
lcPieceHistoryState GetHistoryState() const;
|
|
void SetHistoryState(const lcPieceHistoryState& State, Project* Project, lcGroup* Group);
|
|
|
|
void AddMainModelRenderMeshes(lcScene* Scene, bool Highlight, bool Fade) const;
|
|
void AddSubModelRenderMeshes(lcScene* Scene, const lcMatrix44& WorldMatrix, int DefaultColorIndex, lcRenderMeshState RenderMeshState, bool ParentActive) const;
|
|
void SubModelCompareBoundingBox(const lcMatrix44& WorldMatrix, lcVector3& Min, lcVector3& Max) const;
|
|
void SubModelAddBoundingBoxPoints(const lcMatrix44& WorldMatrix, std::vector<lcVector3>& Points, lcGeometryBoundsMode Mode) const;
|
|
|
|
void InsertTime(lcStep Start, lcStep Time);
|
|
void RemoveTime(lcStep Start, lcStep Time);
|
|
|
|
bool IsHidden() const
|
|
{
|
|
return mHidden;
|
|
}
|
|
|
|
void SetHidden(bool Hidden)
|
|
{
|
|
mHidden = Hidden;
|
|
}
|
|
|
|
const std::vector<lcPieceControlPoint>& GetControlPoints() const
|
|
{
|
|
return mControlPoints;
|
|
}
|
|
|
|
void SetControlPoints(const std::vector<lcPieceControlPoint>& ControlPoints)
|
|
{
|
|
mControlPoints = ControlPoints;
|
|
UpdateMesh();
|
|
}
|
|
|
|
void SetControlPointScale(int ControlPointIndex, float Scale)
|
|
{
|
|
mControlPoints[ControlPointIndex].Scale = Scale;
|
|
UpdateMesh();
|
|
}
|
|
|
|
bool IsTrainTrackConnected(int ConnectionIndex) const
|
|
{
|
|
return mTrainTrackConnections[ConnectionIndex];
|
|
}
|
|
|
|
void SetTrainTrackConnections(std::vector<bool>&& Connections)
|
|
{
|
|
mTrainTrackConnections = std::move(Connections);
|
|
}
|
|
|
|
const QString& GetID() const
|
|
{
|
|
return mID;
|
|
}
|
|
|
|
void UpdateID();
|
|
|
|
QString GetName() const override;
|
|
bool IsVisible(lcStep Step) const;
|
|
bool IsVisibleInSubModel() const;
|
|
|
|
bool AreTrainTrackConnectionsVisible() const
|
|
{
|
|
return IsFocused();
|
|
}
|
|
|
|
void GetModelParts(const lcMatrix44& WorldMatrix, int DefaultColorIndex, std::vector<lcModelPartsEntry>& ModelParts) const;
|
|
void Initialize(const lcMatrix44& WorldMatrix, lcStep Step);
|
|
const lcBoundingBox& GetBoundingBox() const;
|
|
void CompareBoundingBox(lcVector3& Min, lcVector3& Max) const;
|
|
void SetPieceData(lcPieceDataRef PieceDataRef, const QString& ID, bool Wait, bool UpdateSynthInfo);
|
|
bool SetPieceId(lcPieceData* PieceData);
|
|
bool FileLoad(lcFile& file, Project* Project);
|
|
|
|
void UpdatePosition(lcStep Step) override;
|
|
void MoveSelected(lcStep Step, bool AddKey, const lcVector3& Distance);
|
|
void Rotate(lcStep Step, bool AddKey, const lcMatrix33& RotationMatrix, const lcVector3& Center, const lcMatrix33& RotationFrame);
|
|
void MovePivotPoint(const lcVector3& Distance);
|
|
void RotatePivotPoint(const lcMatrix33& RotationMatrix);
|
|
|
|
bool CanAddControlPoint() const;
|
|
bool CanRemoveControlPoint() const;
|
|
|
|
bool InsertControlPoint(const lcVector3& WorldStart, const lcVector3& WorldEnd);
|
|
bool RemoveFocusedControlPoint();
|
|
void VerifyControlPoints(std::vector<lcPieceControlPoint>& ControlPoints) const;
|
|
bool IsGeneratedMeshPending() const { return mSynthPending; }
|
|
// An older mesh may remain visible while its replacement is pending.
|
|
bool HasGeneratedMesh() const { return mMesh != nullptr && !mSynthPending; }
|
|
void SetGeneratedMesh(lcMesh* Mesh);
|
|
void RefreshGeneratedMesh();
|
|
|
|
lcGroup* GetTopGroup();
|
|
|
|
void SetGroup(lcGroup* Group)
|
|
{
|
|
mGroup = Group;
|
|
}
|
|
|
|
lcGroup* GetGroup() const
|
|
{
|
|
return mGroup;
|
|
}
|
|
|
|
lcStep GetStepShow() const
|
|
{
|
|
return mStepShow;
|
|
}
|
|
|
|
lcStep GetStepHide() const
|
|
{
|
|
return mStepHide;
|
|
}
|
|
|
|
void SetStepHide(lcStep Step)
|
|
{
|
|
if (Step < 2)
|
|
Step = 2;
|
|
|
|
mStepHide = Step;
|
|
|
|
if (mStepHide <= mStepShow)
|
|
SetStepShow(mStepHide - 1);
|
|
}
|
|
|
|
void SetStepShow(lcStep Step)
|
|
{
|
|
if (Step == LC_STEP_MAX)
|
|
Step = LC_STEP_MAX - 1;
|
|
|
|
if (mStepShow != Step)
|
|
{
|
|
mFileLine = -1;
|
|
mStepShow = Step;
|
|
}
|
|
|
|
if (mStepHide <= mStepShow)
|
|
mStepHide = mStepShow + 1;
|
|
}
|
|
|
|
quint32 GetColorCode() const
|
|
{
|
|
return mColorCode;
|
|
}
|
|
|
|
void SetColorCode(quint32 ColorCode)
|
|
{
|
|
mColorCode = ColorCode;
|
|
mColorIndex = lcGetColorIndex(ColorCode);
|
|
}
|
|
|
|
int GetColorIndex() const
|
|
{
|
|
return mColorIndex;
|
|
}
|
|
|
|
bool SetColorIndex(int ColorIndex)
|
|
{
|
|
if (mColorIndex == ColorIndex)
|
|
return false;
|
|
|
|
mColorIndex = ColorIndex;
|
|
mColorCode = lcGetColorCode(ColorIndex);
|
|
|
|
return true;
|
|
}
|
|
|
|
void SetPosition(const lcVector3& Position, lcStep Step, bool AddKey)
|
|
{
|
|
mPosition.ChangeKey(Position, Step, AddKey);
|
|
}
|
|
|
|
void SetRotation(const lcMatrix33& Rotation, lcStep Step, bool AddKey)
|
|
{
|
|
mRotation.ChangeKey(Rotation, Step, AddKey);
|
|
}
|
|
|
|
lcVector3 GetRotationCenter() const;
|
|
lcMatrix33 GetRelativeRotation() const;
|
|
|
|
void ResetPivotPoint()
|
|
{
|
|
mPivotPointValid = false;
|
|
mPivotMatrix = lcMatrix44Identity();
|
|
}
|
|
|
|
public:
|
|
lcPieceDataRef mPieceData;
|
|
|
|
lcMatrix44 mModelWorld;
|
|
lcMatrix44 mPivotMatrix = lcMatrix44Identity();
|
|
|
|
protected:
|
|
void UpdateMesh();
|
|
lcMesh* GetDisplayMesh() const;
|
|
|
|
bool IsPivotPointVisible() const
|
|
{
|
|
return mPivotPointValid && IsFocused();
|
|
}
|
|
|
|
bool AreControlPointsVisible() const
|
|
{
|
|
return IsSelected();
|
|
}
|
|
|
|
void DrawSynthInterface(lcContext* Context, const lcMatrix44& WorldMatrix) const;
|
|
|
|
lcObjectProperty<lcVector3> mPosition = lcObjectProperty<lcVector3>(lcVector3(0.0f, 0.0f, 0.0f));
|
|
lcObjectProperty<lcMatrix33> mRotation = lcObjectProperty<lcMatrix33>(lcMatrix33Identity());
|
|
|
|
int mFileLine = -1;
|
|
QString mID;
|
|
|
|
lcGroup* mGroup = nullptr;
|
|
|
|
int mColorIndex;
|
|
quint32 mColorCode;
|
|
|
|
lcStep mStepShow = 1;
|
|
lcStep mStepHide = LC_STEP_MAX;
|
|
|
|
bool mPivotPointValid = false;
|
|
std::vector<lcPieceControlPoint> mControlPoints;
|
|
std::vector<bool> mTrainTrackConnections;
|
|
lcMesh* mMesh = nullptr;
|
|
bool mSynthPending = false;
|
|
};
|