19#include "cameratool.h"
23#include "pointerevent.h"
24#include "layermanager.h"
25#include "selectionmanager.h"
26#include "playbackmanager.h"
27#include "viewmanager.h"
28#include "layercamera.h"
33#include "scribblearea.h"
44CameraTool::~CameraTool()
49void CameraTool::loadSettings()
51 mPropertyEnabled[CAMERAPATH] =
true;
52 connect(mEditor->layers(), &LayerManager::currentLayerChanged,
this, &CameraTool::updateProperties);
53 connect(mEditor, &Editor::objectLoaded,
this, &CameraTool::updateProperties);
55 mRotationIncrement = mEditor->preference()->getInt(SETTING::ROTATION_INCREMENT);
57 connect(mEditor->preference(), &PreferenceManager::optionChanged,
this, &CameraTool::updateSettings);
61 mHandleTextColor =
QColor(0, 0, 0);
68void CameraTool::saveSettings()
72void CameraTool::updateUIAssists(
const Layer* layer)
76 Q_ASSERT(layer->type() == Layer::CAMERA);
78 int currentFrame = mEditor->currentFrame();
79 if (!layer->keyExists(currentFrame)) {
return; }
81 const QTransform& localCamT = camLayer->getViewAtFrame(currentFrame);
82 const QRect& cameraRect = camLayer->getViewRect();
84 mCameraRect = Transform::mapFromLocalRect(localCamT, cameraRect);
85 mCameraPolygon = Transform::mapFromLocalPolygon(localCamT, cameraRect);
87 Camera* cam = camLayer->getLastCameraAtFrame(mEditor->currentFrame(), 0);
89 mRotationHandlePoint = localRotationHandlePoint(cameraRect.
topLeft(), localCamT, cam->scaling(), mEditor->view()->
getScaleInversed());
93void CameraTool::updateProperties()
95 Layer* layer = mEditor->layers()->getLayer(mEditor->currentLayerIndex());
96 if (!layer || layer->type() != Layer::CAMERA) {
return; }
99 properties.cameraPathDotColorType = layerCam->getDotColorType();
100 properties.cameraShowPath = layerCam->getShowCameraPath();
103void CameraTool::updateSettings(
const SETTING setting)
107 case SETTING::ROTATION_INCREMENT:
109 mRotationIncrement = mEditor->preference()->getInt(SETTING::ROTATION_INCREMENT);
122 QPainter cursorPainter(&cursorPixmap);
128 case CameraMoveType::TOPLEFT:
129 case CameraMoveType::BOTTOMRIGHT:
131 moveTypeImage =
QImage(
"://icons/general/cursor-diagonal-left.svg");
134 case CameraMoveType::TOPRIGHT:
135 case CameraMoveType::BOTTOMLEFT:
137 moveTypeImage =
QImage(
"://icons/general/cursor-diagonal-right.svg");
140 case CameraMoveType::ROTATION:
142 moveTypeImage =
QImage(
"://icons/general/cursor-rotate.svg");
145 case CameraMoveType::PATH:
146 case CameraMoveType::CENTER:
148 moveTypeImage =
QImage(
"://icons/general/cursor-move.svg");
160 rotT.
rotate(mCurrentAngle);
162 cursorPainter.setTransform(rotT);
163 cursorPainter.drawImage(offset, moveTypeImage);
169void CameraTool::updateMoveMode(
const QPointF& pos)
172 if (mScribbleArea->isPointerInUse()) {
177 Layer* layer = mEditor->layers()->currentLayer();
178 mCamMoveMode = CameraMoveType::NONE;
179 qreal selectionTolerance = mEditor->select()->selectionTolerance();
181 Q_ASSERT(layer->type() == Layer::CAMERA);
183 if (layer->keyExists(mEditor->currentFrame()))
185 mCamMoveMode = getCameraMoveMode(pos,
187 }
else if (properties.cameraShowPath) {
188 int keyPos = cam->firstKeyFramePosition();
189 while (keyPos <= cam->getMaxKeyFramePosition())
191 mCamMoveMode = getPathMoveMode(cam,
195 if (mCamMoveMode != CameraMoveType::NONE)
197 mDragPathFrame = keyPos;
201 if (keyPos == cam->getNextKeyFramePosition(keyPos)) {
205 keyPos = cam->getNextKeyFramePosition(keyPos);
210void CameraTool::setShowCameraPath(
const bool showCameraPath)
214 Q_ASSERT(layer->type() == Layer::CAMERA);
215 layer->setShowCameraPath(showCameraPath);
217 properties.cameraShowPath = showCameraPath;
220void CameraTool::setPathDotColorType(
const DotColorType pathDotColor)
223 Q_ASSERT(layer->type() == Layer::CAMERA);
225 layer->updateDotColor(pathDotColor);
228void CameraTool::resetCameraPath()
231 Q_ASSERT(layer->type() == Layer::CAMERA);
233 layer->setPathMovedAtFrame(mEditor->currentFrame(),
false);
237void CameraTool::resetTransform(CameraFieldOption option)
240 Q_ASSERT(layer->type() == Layer::CAMERA);
242 if (option == CameraFieldOption::RESET_ROTATION || option == CameraFieldOption::RESET_FIELD) {
246 layer->resetCameraAtFrame(option, mEditor->currentFrame());
252 Q_ASSERT(editor()->layers()->currentLayer()->type() == Layer::CAMERA);
256 if (mCamMoveMode == CameraMoveType::ROTATION) {
257 angleDeg = getAngleBetween(pos, mCameraRect.
center()) - mStartAngle;
259 angleDeg = constrainedRotation(angleDeg, mRotationIncrement);
261 mCurrentAngle = angleDeg;
264 transformView(layer, mCamMoveMode, pos, mTransformOffset, -angleDeg, mEditor->currentFrame());
267 mTransformOffset = pos;
270void CameraTool::transformCameraPath(
const QPointF& pos)
272 Q_ASSERT(editor()->layers()->currentLayer()->type() == Layer::CAMERA);
275 layer->updatePathControlPointAtFrame(pos, mDragPathFrame);
279int CameraTool::constrainedRotation(
const qreal rotatedAngle,
const int rotationIncrement)
const
281 return qRound(rotatedAngle / rotationIncrement) * rotationIncrement;
286 updateMoveMode(
event->canvasPos());
287 updateUIAssists(mEditor->layers()->currentLayer());
289 mStartAngle = getAngleBetween(
event->canvasPos(), mCameraRect.
center()) - mCurrentAngle;
290 mTransformOffset =
event->canvasPos();
295 Layer* currentLayer = mEditor->layers()->currentLayer();
296 updateMoveMode(
event->canvasPos());
297 updateUIAssists(currentLayer);
299 if (mScribbleArea->isPointerInUse())
301 if (currentLayer->keyExists(mEditor->currentFrame())) {
302 transformCamera(
event->canvasPos(),
event->modifiers());
304 else if (mCamMoveMode == CameraMoveType::PATH)
306 transformCameraPath(
event->canvasPos());
309 mScribbleArea->updateToolCursor();
310 mEditor->view()->forceUpdateViewTransform();
314void CameraTool::pointerReleaseEvent(
PointerEvent* event)
316 Layer* layer = editor()->layers()->currentLayer();
317 updateMoveMode(
event->canvasPos());
318 updateUIAssists(layer);
320 int frame = mEditor->currentFrame();
321 if (layer->keyExists(frame)) {
322 transformCamera(
event->canvasPos(),
event->modifiers());
323 mEditor->view()->forceUpdateViewTransform();
324 }
else if (mCamMoveMode == CameraMoveType::PATH) {
325 transformCameraPath(
event->canvasPos());
326 mEditor->view()->forceUpdateViewTransform();
331qreal CameraTool::getAngleBetween(
const QPointF& pos1,
const QPointF& pos2)
const
333 return qRadiansToDegrees(MathUtils::getDifferenceAngle(pos1, pos2));
336CameraMoveType CameraTool::getCameraMoveMode(
const QPointF& point, qreal tolerance)
const
340 if (camPoly.
count() <= 0) {
return CameraMoveType::NONE; }
344 return CameraMoveType::TOPLEFT;
348 return CameraMoveType::TOPRIGHT;
352 return CameraMoveType::BOTTOMRIGHT;
356 return CameraMoveType::BOTTOMLEFT;
358 else if (
QLineF(point, mRotationHandlePoint).length() < tolerance)
360 return CameraMoveType::ROTATION;
364 return CameraMoveType::CENTER;
366 return CameraMoveType::NONE;
369CameraMoveType CameraTool::getPathMoveMode(
const LayerCamera* layerCamera,
int frameNumber,
const QPointF& point, qreal tolerance)
const
371 int prev = layerCamera->getPreviousKeyFramePosition(frameNumber);
372 int next = layerCamera->getNextKeyFramePosition(frameNumber);
373 if (layerCamera->hasSameTranslation(prev, next))
374 return CameraMoveType::NONE;
376 Camera* camera = layerCamera->getLastCameraAtFrame(frameNumber, 0);
378 if (camera ==
nullptr) {
return CameraMoveType::NONE; }
380 QPointF pathPoint = camera->getPathControlPoint();
382 if (!camera->pathControlPointMoved()) {
383 pathPoint = layerCamera->getCenteredPathPoint(frameNumber);
386 if (
QLineF(pathPoint, point).length() < tolerance) {
387 return CameraMoveType::PATH;
389 return CameraMoveType::NONE;
393QPointF CameraTool::localRotationHandlePoint(
const QPoint& origin,
const QTransform& localT,
const qreal objectScale,
float worldScale)
const
397 qreal topDis = origin.
y() + ((objectScale * origin.
y()) * mRotationHandleOffsetPercentage) * worldScale;
401QPointF CameraTool::worldRotationHandlePoint(
const QPoint& origin,
const QTransform& localT,
const qreal objectScale,
const QTransform& worldT,
float worldScale)
const
403 return worldT.
map(localRotationHandlePoint(origin, localT, objectScale, worldScale));
406void CameraTool::transformView(
LayerCamera* layerCamera, CameraMoveType mode,
const QPointF& point,
const QPointF& offset, qreal angle,
int frameNumber)
const
410 QLineF lineOld(curCenter, point);
411 QLineF lineNew(curCenter, point);
412 Camera* curCam = layerCamera->getCameraAtFrame(frameNumber);
416 case CameraMoveType::CENTER: {
417 curCam->translate(curCam->translation() - (point - offset));
420 case CameraMoveType::TOPLEFT:
421 lineOld.setP2(curPoly.
at(0));
422 curCam->scale(curCam->scaling() * (lineOld.length() / lineNew.length()));
424 case CameraMoveType::TOPRIGHT:
425 lineOld.setP2(curPoly.
at(1));
426 curCam->scale(curCam->scaling() * (lineOld.length() / lineNew.length()));
428 case CameraMoveType::BOTTOMRIGHT:
429 lineOld.setP2(curPoly.
at(2));
430 curCam->scale(curCam->scaling() * (lineOld.length() / lineNew.length()));
432 case CameraMoveType::BOTTOMLEFT:
433 lineOld.setP2(curPoly.
at(3));
434 curCam->scale(curCam->scaling() * (lineOld.length() / lineNew.length()));
436 case CameraMoveType::ROTATION:
437 curCam->rotate(angle);
442 curCam->updateViewTransform();
443 curCam->modification();
448 int frameIndex = mEditor->currentFrame();
449 LayerCamera* cameraLayerBelow =
static_cast<LayerCamera*
>(mEditor->object()->getLayerBelow(mEditor->currentLayerIndex(), Layer::CAMERA));
451 const QTransform& camTransform = cameraLayerBelow->getViewAtFrame(frameIndex);
452 const QRect& cameraRect = cameraLayerBelow->getViewRect();
453 const QTransform& worldT = mEditor->view()->getView();
455 bool isPlaying = mEditor->playback()->isPlaying();
460 int frame = cameraLayerBelow->getPreviousKeyFramePosition(frameIndex);
461 Camera* cam = cameraLayerBelow->getLastCameraAtFrame(qMax(frame, frameIndex), 0);
463 qreal scale = cam->scaling();
464 qreal rotation = cam->rotation();
465 QPointF translation = cam->translation();
466 paintHandles(painter, worldT, camTransform, cameraRect, translation, scale, rotation, !cameraLayerBelow->keyExists(frameIndex));
469 cameraLayerBelow->foreachKeyFrame([&] (
const KeyFrame* keyframe) {
470 paintInterpolations(painter, worldT, frameIndex, cameraLayerBelow,
static_cast<const Camera*
>(keyframe), isPlaying);
475void CameraTool::paintHandles(
QPainter& painter,
const QTransform& worldTransform,
const QTransform& camTransform,
const QRect& cameraRect,
const QPointF translation,
const qreal scale,
const qreal rotation,
bool hollowHandles)
const
490 const QPolygonF& camPolygon = Transform::mapToWorldPolygon(camTransform, worldTransform, cameraRect);
496 scaleT.
translate(translation.
x(), translation.
y());
498 const QPolygonF& nonScaledCamPoly = Transform::mapToWorldPolygon(scaleT, worldTransform, cameraRect);
503 painter.
setPen(mHandleDisabledColor);
506 painter.
setPen(mHandlePen);
509 int handleW = mHandleWidth;
510 int radius = handleW / 2;
512 const QRectF& topRightCorner =
QRectF(camPolygon.
at(1).x() - radius,
513 camPolygon.
at(1).y() - radius,
517 const QRectF& bottomRightCorner =
QRectF(camPolygon.
at(2).x() - radius,
518 camPolygon.
at(2).y() - radius,
520 painter.
drawRect(bottomRightCorner);
521 const QRectF& topLeftCorner =
QRectF(camPolygon.
at(0).x() - radius,
522 camPolygon.
at(0).y() - radius,
526 const QRectF& bottomLeftCorner =
QRectF(camPolygon.
at(3).x() - radius,
527 camPolygon.
at(3).y() - radius,
533 const QPointF& rotationHandle = worldRotationHandlePoint(cameraRect.
topLeft(), camTransform, scale, worldTransform, mEditor->viewScaleInversed());
535 painter.
drawLine(topCenter, rotationHandle);
538 (rotationHandle.
y() - handleW*0.5),
544void CameraTool::paintInterpolations(
QPainter& painter,
const QTransform& worldTransform,
int currentFrame,
const LayerCamera* cameraLayer,
const Camera* keyframe,
bool isPlaying)
const
546 QColor cameraDotColor = cameraLayer->getDotColor();
547 int frame = keyframe->pos();
548 int nextFrame = cameraLayer->getNextKeyFramePosition(frame);
550 if (cameraLayer->getShowCameraPath() && !cameraLayer->hasSameTranslation(frame, nextFrame)) {
559 const QRect& cameraRect = cameraLayer->getViewRect();
560 const QTransform& cameraTransform = cameraLayer->getViewAtFrame(currentFrame);
561 const QPointF& centerDot = Transform::mapToWorldRect(cameraTransform, worldTransform, cameraRect).
center();
562 painter.
drawEllipse(centerDot, mDotWidth/2., mDotWidth/2.);
565 if (!keyframe->pathControlPointMoved()) {
566 cameraPathPoint = worldTransform.
map(cameraLayer->getCenteredPathPoint(frame + 1));
568 cameraPathPoint = worldTransform.
map(cameraLayer->getPathControlPointAtFrame(frame + 1));
572 QColor color = cameraDotColor;
573 if (currentFrame > frame && currentFrame < nextFrame)
580 for (
int frameInBetween = frame; frameInBetween <= nextFrame ; frameInBetween++)
582 const QTransform& transform = cameraLayer->getViewAtFrame(frameInBetween);
583 const QPointF&
center = Transform::mapToWorldRect(transform, worldTransform, cameraRect).
center();
584 painter.
drawEllipse(center, mDotWidth/2., mDotWidth/2.);
588 int distance = nextFrame - frame;
590 if (distance >= 2 && !isPlaying) {
591 paintControlPoint(painter, worldTransform, cameraLayer, frame, cameraPathPoint, cameraLayer->keyExists(currentFrame));
598void CameraTool::paintControlPoint(
QPainter& painter,
const QTransform& worldTransform,
const LayerCamera* cameraLayer,
const int frameIndex,
const QPointF& pathPoint,
bool hollowHandle)
const
603 const QList<QPointF>& points = cameraLayer->getBezierPointsAtFrame(frameIndex + 1);
607 Q_ASSERT(points.
size() == 3);
622 const QString& pathType = cameraLayer->getInterpolationTextAtFrame(frameIndex);
630 painter.
setPen(mHandleTextColor);
633 painter.
setPen(mHandleDisabledColor);
636 painter.
setPen(mHandlePen);
639 painter.
drawRect(
static_cast<int>(pathPoint.
x() - mHandleWidth/2),
640 static_cast<int>(pathPoint.
y() - mHandleWidth/2),
641 mHandleWidth, mHandleWidth);
void frameModified(int frameNumber)
This should be emitted after modifying the frame content.
void updateFrame()
Will call update() and update the canvas Only call this directly If you need the cache to be intact a...
qreal getScaleInversed() const
void setAlphaF(qreal alpha)
qreal length() const const
QPointF pointAt(qreal t) const const
const T & at(int i) const const
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
virtual bool event(QEvent *e)
void drawEllipse(const QRectF &rectangle)
void drawLine(const QLineF &line)
void drawPolygon(const QPointF *points, int pointCount, Qt::FillRule fillRule)
void drawRect(const QRectF &rectangle)
void drawText(const QPointF &position, const QString &text)
void setBrush(const QBrush &brush)
void setPen(const QColor &color)
void setColor(const QColor &color)
void fill(const QColor &color)
QPoint toPoint() const const
bool containsPoint(const QPointF &point, Qt::FillRule fillRule) const const
QPoint topLeft() const const
QPointF center() const const
typedef KeyboardModifiers
QTextStream & center(QTextStream &stream)
const T & at(int i) const const
int count(const T &value) const const