initial commit
This commit is contained in:
1327
client/gui/editor/EditorCanvas.cpp
Normal file
1327
client/gui/editor/EditorCanvas.cpp
Normal file
File diff suppressed because it is too large
Load Diff
179
client/gui/editor/EditorCanvas.h
Normal file
179
client/gui/editor/EditorCanvas.h
Normal file
@@ -0,0 +1,179 @@
|
||||
#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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user