Files
leocad/common/lc_view.h
T
Leonardo Zide baae697960 Fix in-place submodel editing context and navigation
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.
2026-10-24 12:39:25 -07:00

411 lines
9.0 KiB
C++

#pragma once
#include "lc_assettypes.h"
#include "lc_context.h"
#include "lc_math.h"
#include "lc_commands.h"
#include "lc_result.h"
struct lcInsertPieceInfo;
enum class lcCameraProjection;
enum class lcDragState
{
None,
Piece,
Color
};
enum class lcCursor
{
First,
Hidden = First,
Default,
Brick,
PointLight,
SpotLight,
DirectionalLight,
AreaLight,
Camera,
Select,
SelectAdd,
SelectRemove,
Move,
Rotate,
RotateX,
RotateY,
Delete,
Paint,
ColorPicker,
Zoom,
ZoomRegion,
Pan,
Roll,
RotateView,
Count
};
enum class lcTrackButton
{
None,
Left,
Middle,
Right
};
enum class lcTrackTool
{
None,
Insert,
PointLight,
SpotLight,
DirectionalLight,
AreaLight,
Camera,
Select,
MoveX,
MoveY,
MoveZ,
MoveXY,
MoveXZ,
MoveYZ,
MoveXYZ,
RotateX,
RotateY,
RotateZ,
RotateTrackBall,
RotateCamera,
RotateTrainTrackRight,
RotateTrainTrackLeft,
InsertTrainTrack,
SelectTrainTrack,
ScalePlus,
ScaleMinus,
Eraser,
Paint,
ColorPicker,
Zoom,
Pan,
OrbitX,
OrbitY,
OrbitXY,
Roll,
ZoomRegion,
Count
};
enum class lcViewType
{
View,
Preview,
Minifig,
PartsList,
Count
};
struct lcFindReplaceParams
{
lcPieceData* FindPieceData = nullptr;
QString FindString;
int FindColorIndex = 0;
lcPieceData* ReplacePieceData = nullptr;
int ReplaceColorIndex = 0;
};
class lcView : public QObject
{
Q_OBJECT
public:
lcView(lcViewType ViewType, lcModel* Model);
~lcView();
lcView(const lcView&) = delete;
lcView(lcView&&) = delete;
lcView& operator=(const lcView&) = delete;
lcView& operator=(lcView&&) = delete;
static lcFindReplaceParams& GetFindReplaceParams()
{
return mFindReplaceParams;
}
lcModel* GetModel() const
{
return mModel;
}
lcViewType GetViewType() const
{
return mViewType;
}
lcCamera* GetCamera() const
{
return mCamera;
}
bool IsLastFocused() const
{
return mLastFocusedView == this;
}
bool IsTracking() const
{
return mTrackButton != lcTrackButton::None;
}
int GetWidth() const
{
return mWidth;
}
int GetHeight() const
{
return mHeight;
}
void SetSize(int Width, int Height)
{
mWidth = Width;
mHeight = Height;
}
lcViewWidget* GetWidget() const
{
return mWidget;
}
void SetWidget(lcViewWidget* Widget)
{
mWidget = Widget;
}
int GetMouseX() const
{
return mMouseX;
}
int GetMouseY() const
{
return mMouseY;
}
int GetMouseDownX() const
{
return mMouseDownX;
}
int GetMouseDownY() const
{
return mMouseDownY;
}
float GetCameraRotationStartAngle() const
{
return mCameraRotationMouseAngle;
}
void SetBackgroundColorOverride(quint32 BackgroundColor)
{
mOverrideBackgroundColor = true;
mBackgroundColor = BackgroundColor;
}
lcMatrix44 GetActiveSubmodelTransform() const
{
return mActiveSubmodelTransform;
}
static std::vector<lcView*> GetModelViews(const lcModel* Model);
static void UpdateProjectViews(const Project* Project);
static void UpdateAllViews();
static void CreateResources(lcContext* Context);
static void DestroyResources(lcContext* Context);
void MakeCurrent();
bool PrepareOutlineFramebuffers();
void Redraw();
void SetOffscreenContext();
void SetFocus(bool Focus);
void SetMousePosition(int MouseX, int MouseY);
void SetMouseModifiers(Qt::KeyboardModifiers MouseModifiers);
lcModel* GetActiveModel() const;
std::vector<lcModel*> GetModelEditingPath() const;
void SetSubmodelActive(size_t Depth);
void SetTopSubmodelActive();
void SetSelectedSubmodelActive();
void OnDraw();
bool HasMissingAssets() const;
void OnLeftButtonDown();
void OnLeftButtonUp();
void OnLeftButtonDoubleClick();
void OnMiddleButtonDown();
void OnMiddleButtonUp();
void OnRightButtonDown();
void OnRightButtonUp();
void OnBackButtonDown();
void OnBackButtonUp();
void OnForwardButtonDown();
void OnForwardButtonUp();
void OnMouseMove();
void OnMouseLeave();
void OnMouseWheel(float Direction);
void BeginDrag(lcDragState DragState);
void EndDrag(bool Accept);
void UpdateCursor();
void StartPanGesture();
void UpdatePanGesture(int dx, int dy);
void EndPanGesture(bool Accept);
void StartOrbitTracking();
void StopTracking(bool Accept);
void CancelTrackingOrClearSelectionAction();
void SetViewpoint(lcViewpoint Viewpoint);
void SetViewpoint(const lcVector3& Position);
void SetViewpoint(const lcVector3& Position, const lcVector3& Target, const lcVector3& Up);
void SetCameraAngles(float Latitude, float Longitude);
void SetDefaultCamera();
void SetCamera(lcCamera* Camera, bool ForceCopy);
void SetCamera(const QString& CameraName);
void SetCameraIndex(size_t CameraIndex);
void SetCameraProjection(lcCameraProjection CameraProjection);
void LookAt();
void MoveCamera(const lcVector3& Direction);
void Zoom(float Amount);
void ZoomExtents(lcGeometryBoundsMode Mode, bool AdjustFarPlane);
void ZoomExtentsAtStep(lcStep Step, lcGeometryBoundsMode Mode, bool AdjustFarPlane);
void RemoveCamera();
void ShowContextMenu() const;
bool CloseFindReplaceDialog();
void ShowFindReplaceWidget(bool Replace);
float GetUIScale() const;
float GetOverlayScale() const;
lcVector3 GetMoveDirection(const lcVector3& Direction) const;
void UpdatePiecePreview();
std::pair<std::vector<lcInsertPieceInfo>, bool> GetMouseInsertPieceInfo(bool IgnoreSelected, bool AllowNewPieces, const lcPieceDataRef& PieceData, lcPiece* MovingPiece) const;
lcVector3 GetCameraLightInsertPosition() const;
void GetRayUnderPointer(lcVector3& Start, lcVector3& End) const;
lcObjectRayTest RayTest(bool PiecesOnly, bool IgnoreSelected) const;
lcObjectSection FindObjectUnderPointer(bool PiecesOnly, bool IgnoreSelected) const;
std::vector<lcObject*> FindObjectsInBox(float x1, float y1, float x2, float y2) const;
lcVector3 ProjectPoint(const lcVector3& Point) const;
lcVector3 UnprojectPoint(const lcVector3& Point) const;
void UnprojectPoints(lcVector3* Points, int NumPoints) const;
lcMatrix44 GetProjectionMatrix() const;
bool BeginRenderToImage(int Width, int Height);
void EndRenderToImage();
QImage GetRenderImage() const;
void BindRenderFramebuffer();
void UnbindRenderFramebuffer();
QImage GetRenderFramebufferImage() const;
std::vector<QImage> GetStepImages(lcStep Start, lcStep End);
lcResult<void> SaveStepImages(const QString& BaseName, bool AddStepSuffix, lcStep Start, lcStep End, std::function<void(const QString&)> ProgressCallback);
lcContext* mContext = nullptr;
signals:
void FocusReceived();
protected:
void DestroyOutlineFramebuffers();
bool GenerateOutlineMasks();
void DrawBackground(int CurrentTileRow, int TotalTileRows, int CurrentTileHeight) const;
void DrawViewport() const;
void DrawAxes() const;
void DrawSelectZoomRegionOverlay();
void DrawRotateViewOverlay();
void DrawGrid();
lcMatrix44 GetTileProjectionMatrix(int CurrentRow, int CurrentColumn, int CurrentTileWidth, int CurrentTileHeight) const;
lcCursor GetCursor() const;
void SetCursor(lcCursor Cursor);
lcTool GetCurrentTool() const;
void UpdateTrackTool();
lcTrackTool GetOverrideTrackTool(Qt::MouseButton Button) const;
void StartTracking(lcTrackButton TrackButton);
void OnButtonDown(lcTrackButton TrackButton);
void StartPan(int x, int y);
void UpdatePan(int x, int y);
lcVector3 GetTrackballPoint(int x, int y) const;
void ShowTrainTrackPopup();
lcViewWidget* mWidget = nullptr;
int mWidth = 1;
int mHeight = 1;
lcViewType mViewType;
int mMouseX = 0;
int mMouseY = 0;
int mMouseDownX = 0;
int mMouseDownY = 0;
float mCameraRotationMouseAngle = 0.0f;
float mCameraRotationLastMouseAngle = 0.0f;
float mCameraRotationAngle = 0.0f;
lcVector3 mTrackballCenter;
lcVector3 mTrackballVector;
float mTrackballRadius = 1.0f;
lcMatrix33 mTrackballPendingRotation = lcMatrix33Identity();
bool mTrackballSnapping = false;
bool mTrackballHasPendingRotation = false;
Qt::KeyboardModifiers mMouseModifiers = Qt::NoModifier;
bool mTrackUpdated = false;
bool mToolClicked = false;
lcTrackTool mTrackTool = lcTrackTool::None;
lcTrackButton mTrackButton = lcTrackButton::None;
lcCursor mCursor = lcCursor::Default;
lcDragState mDragState;
bool mTrackToolFromOverlay;
quint32 mTrackToolSection = ~0U;
lcMatrix44 mMouseDownTransform;
lcPiece* mMouseDownPiece = nullptr;
int mPanX = 0;
int mPanY = 0;
QImage mRenderImage;
std::unique_ptr<QOpenGLFramebufferObject> mRenderFramebuffer;
std::unique_ptr<QOpenGLFramebufferObject> mOutlineFullFramebuffer;
std::unique_ptr<QOpenGLFramebufferObject> mOutlineVisibleFramebuffer;
QSize mOutlineAttemptSize;
QPointer<QOpenGLContext> mOutlineGLContext;
bool mOverrideBackgroundColor = false;
quint32 mBackgroundColor = 0;
std::unique_ptr<lcScene> mScene;
std::unique_ptr<lcViewManipulator> mViewManipulator;
std::unique_ptr<lcViewSphere> mViewSphere;
lcModel* mModel = nullptr;
lcPiece* mActiveSubmodelInstance = nullptr;
lcMatrix44 mActiveSubmodelTransform;
std::vector<std::pair<lcPiece*, lcMatrix44>> mSubmodelEditingPath;
lcCamera* mCamera = nullptr;
lcVertexBuffer mGridBuffer;
int mGridSettings[7];
static QPointer<lcFindReplaceWidget> mFindWidget;
static lcFindReplaceParams mFindReplaceParams;
static lcView* mLastFocusedView;
static std::vector<lcView*> mViews;
};