180 lines
6.6 KiB
C++
180 lines
6.6 KiB
C++
#pragma once
|
||
|
||
#include "core/domain/Project.h"
|
||
|
||
#include <QPixmap>
|
||
#include <QPointF>
|
||
#include <QImage>
|
||
#include <QPainterPath>
|
||
#include <QVector>
|
||
#include <QWidget>
|
||
#include <QElapsedTimer>
|
||
|
||
class EditorCanvas final : public QWidget {
|
||
Q_OBJECT
|
||
public:
|
||
enum class Tool { Move, Zoom, CreateEntity };
|
||
Q_ENUM(Tool)
|
||
|
||
explicit EditorCanvas(QWidget* parent = nullptr);
|
||
|
||
void setBackgroundImagePath(const QString& absolutePath);
|
||
QString backgroundImagePath() const { return m_bgAbsPath; }
|
||
void setBackgroundVisible(bool on);
|
||
bool backgroundVisible() const { return m_backgroundVisible; }
|
||
|
||
void setDepthMapPath(const QString& absolutePath);
|
||
void setDepthOverlayEnabled(bool on);
|
||
bool depthOverlayEnabled() const { return m_depthOverlayEnabled; }
|
||
|
||
void setTool(Tool tool);
|
||
Tool tool() const { return m_tool; }
|
||
|
||
void resetView();
|
||
void zoomToFit();
|
||
|
||
void setWorldAxesVisible(bool on);
|
||
bool worldAxesVisible() const { return m_worldAxesVisible; }
|
||
|
||
void setAxisLabelsVisible(bool on);
|
||
bool axisLabelsVisible() const { return m_axisLabelsVisible; }
|
||
|
||
void setGizmoLabelsVisible(bool on);
|
||
bool gizmoLabelsVisible() const { return m_gizmoLabelsVisible; }
|
||
|
||
void setGridVisible(bool on);
|
||
bool gridVisible() const { return m_gridVisible; }
|
||
|
||
void setCheckerboardVisible(bool on);
|
||
bool checkerboardVisible() const { return m_checkerboardVisible; }
|
||
|
||
// 预览呈现:完整背景 + 全部实体(忽略显隐开关),隐藏编辑辅助元素,仅可平移/缩放查看
|
||
void setPresentationPreviewMode(bool on);
|
||
bool presentationPreviewMode() const { return m_presentationPreviewMode; }
|
||
|
||
void setEntities(const QVector<core::Project::Entity>& entities, const QString& projectDirAbs);
|
||
void setCurrentFrame(int frame);
|
||
int currentFrame() const { return m_currentFrame; }
|
||
|
||
bool isDraggingEntity() const { return m_draggingEntity; }
|
||
|
||
void selectEntityById(const QString& id);
|
||
void clearEntitySelection();
|
||
|
||
// 与动画求值一致的原点/缩放(用于 K 帧与自动关键帧)
|
||
QPointF selectedAnimatedOriginWorld() const;
|
||
double selectedDepthScale01() const;
|
||
QPointF selectedEntityCentroidWorld() const;
|
||
double selectedDistanceScaleMultiplier() const;
|
||
double selectedUserScale() const;
|
||
double selectedCombinedScale() const;
|
||
|
||
enum class DragMode { None, Free, AxisX, AxisY };
|
||
|
||
signals:
|
||
void hoveredWorldPosChanged(const QPointF& worldPos);
|
||
void hoveredWorldPosDepthChanged(const QPointF& worldPos, int depthZ);
|
||
void selectedEntityChanged(bool hasSelection, const QString& id, int depth, const QPointF& originWorld);
|
||
void requestAddEntity(const core::Project::Entity& entity, const QImage& image);
|
||
void requestMoveEntity(const QString& id, const QPointF& delta);
|
||
void entityDragActiveChanged(bool on);
|
||
void selectedEntityPreviewChanged(const QString& id, int depth, const QPointF& originWorld);
|
||
|
||
protected:
|
||
void paintEvent(QPaintEvent* e) override;
|
||
void resizeEvent(QResizeEvent* e) override;
|
||
void mousePressEvent(QMouseEvent* e) override;
|
||
void mouseMoveEvent(QMouseEvent* e) override;
|
||
void mouseReleaseEvent(QMouseEvent* e) override;
|
||
void wheelEvent(QWheelEvent* e) override;
|
||
|
||
private:
|
||
void ensurePixmapLoaded() const;
|
||
void invalidatePixmap();
|
||
void updateCursor();
|
||
|
||
QPointF viewToWorld(const QPointF& v) const;
|
||
QPointF worldToView(const QPointF& w) const;
|
||
QRectF worldRectOfBackground() const;
|
||
|
||
private:
|
||
struct Entity {
|
||
QString id;
|
||
QRectF rect; // world 坐标(用于拖拽与约束)
|
||
QVector<QPointF> polygonWorld; // 非空则使用 polygon
|
||
QPainterPath pathWorld; // polygonWorld 对应的 world 路径(缓存,避免每帧重建)
|
||
QVector<QPointF> cutoutPolygonWorld;
|
||
QColor color;
|
||
|
||
// 实体独立信息:
|
||
int depth = 0; // 0..255,来自划分区域平均深度
|
||
QImage image; // 抠图后的实体图像(带透明)
|
||
QPointF imageTopLeft; // image 对应的 world 左上角
|
||
double visualScale = 1.0; // 实体在 world 坐标下的缩放(用于贴图绘制)
|
||
double userScale = 1.0; // 与深度距离缩放相乘
|
||
QPointF animatedOriginWorld;
|
||
double animatedDepthScale01 = 0.5;
|
||
// 编辑模式下实体被设为隐藏时:不响应点选且不绘制,除非当前选中(便于树选隐藏实体)
|
||
bool hiddenInEditMode = false;
|
||
};
|
||
int hitTestEntity(const QPointF& worldPos) const;
|
||
|
||
private:
|
||
QString m_bgAbsPath;
|
||
bool m_backgroundVisible = true;
|
||
mutable QPixmap m_bgPixmap;
|
||
mutable bool m_pixmapDirty = true;
|
||
mutable QImage m_bgImage; // 原背景(用于抠图/填充)
|
||
mutable QImage m_bgImageCutout; // 抠图后的背景(实体区域填黑)
|
||
mutable bool m_bgImageDirty = true;
|
||
mutable bool m_bgCutoutDirty = true;
|
||
|
||
QString m_depthAbsPath;
|
||
mutable QImage m_depthImage8;
|
||
mutable bool m_depthDirty = true;
|
||
bool m_depthOverlayEnabled = false;
|
||
int m_depthOverlayAlpha = 110;
|
||
bool m_worldAxesVisible = true;
|
||
bool m_axisLabelsVisible = true;
|
||
bool m_gizmoLabelsVisible = true;
|
||
bool m_gridVisible = true;
|
||
bool m_checkerboardVisible = true;
|
||
bool m_presentationPreviewMode = false;
|
||
|
||
Tool m_tool = Tool::Move;
|
||
qreal m_scale = 1.0;
|
||
QPointF m_pan; // world 原点对应的 view 坐标偏移(view = world*scale + pan)
|
||
|
||
bool m_dragging = false;
|
||
bool m_draggingEntity = false;
|
||
bool m_drawingEntity = false;
|
||
QPointF m_lastMouseView;
|
||
// 拖动以“实体原点 animatedOriginWorld”为基准,避免因缩放导致 rect/topLeft 抖动
|
||
QPointF m_entityDragOffsetOriginWorld;
|
||
QPointF m_entityDragStartAnimatedOrigin;
|
||
// 拖动性能优化:拖动过程中不逐点修改 polygonWorld,而是保留基准形状+增量参数,在 paint 时做变换预览
|
||
bool m_dragPreviewActive = false;
|
||
QVector<QPointF> m_dragPolyBase;
|
||
QPainterPath m_dragPathBase;
|
||
QPointF m_dragImageTopLeftBase;
|
||
QRectF m_dragRectBase;
|
||
QPointF m_dragOriginBase;
|
||
QPointF m_dragDelta; // 纯平移
|
||
QPointF m_dragCentroidBase;
|
||
double m_dragScaleBase = 1.0; // 拖动开始时的 visualScale
|
||
double m_dragScaleRatio = 1.0; // 相对 m_dragScaleBase 的缩放比(由深度重算驱动)
|
||
QElapsedTimer m_previewEmitTimer;
|
||
qint64 m_lastPreviewEmitMs = 0;
|
||
qint64 m_lastDepthScaleRecalcMs = 0;
|
||
int m_selectedEntity = -1;
|
||
|
||
DragMode m_dragMode = DragMode::None;
|
||
QPointF m_dragStartMouseWorld;
|
||
|
||
QVector<Entity> m_entities;
|
||
QVector<QPointF> m_strokeWorld;
|
||
|
||
int m_currentFrame = 0;
|
||
};
|
||
|