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()
48void CameraTool::loadSettings()
50 mPropertyEnabled[CAMERAPATH] =
true;
51 connect(mEditor->layers(), &LayerManager::currentLayerChanged,
this, &CameraTool::updateProperties);
52 connect(mEditor, &Editor::objectLoaded,
this, &CameraTool::updateProperties);
54 mRotationIncrement = mEditor->preference()->getInt(SETTING::ROTATION_INCREMENT);
56 connect(mEditor->preference(), &PreferenceManager::optionChanged,
this, &CameraTool::updateSettings);
60 mHandleTextColor =
QColor(0, 0, 0);
67void CameraTool::updateUIAssists(
const Layer* layer)
71 Q_ASSERT(layer->type() == Layer::CAMERA);
73 int currentFrame = mEditor->currentFrame();
74 if (!layer->keyExists(currentFrame)) {
return; }
76 const QTransform& localCamT = camLayer->getViewAtFrame(currentFrame);
77 const QRect& cameraRect = camLayer->getViewRect();
79 mCameraRect = Transform::mapFromLocalRect(localCamT, cameraRect);
80 mCameraPolygon = Transform::mapFromLocalPolygon(localCamT, cameraRect);
82 Camera* cam = camLayer->getLastCameraAtFrame(mEditor->currentFrame(), 0);
84 mRotationHandlePoint = localRotationHandlePoint(cameraRect.
topLeft(), localCamT, cam->scaling(), mEditor->view()->getViewScaleInverse());
88void CameraTool::updateProperties()
90 Layer* layer = mEditor->layers()->getLayer(mEditor->currentLayerIndex());
91 if (!layer || layer->type() != Layer::CAMERA) {
return; }
94 properties.cameraPathDotColorType = layerCam->getDotColorType();
95 properties.cameraShowPath = layerCam->getShowCameraPath();
98void CameraTool::updateSettings(
const SETTING setting)
102 case SETTING::ROTATION_INCREMENT:
104 mRotationIncrement = mEditor->preference()->getInt(SETTING::ROTATION_INCREMENT);
117 QPainter cursorPainter(&cursorPixmap);
123 case CameraMoveType::TOPLEFT:
124 case CameraMoveType::BOTTOMRIGHT:
126 moveTypeImage =
QImage(
"://icons/general/cursor-diagonal-left.svg");
129 case CameraMoveType::TOPRIGHT:
130 case CameraMoveType::BOTTOMLEFT:
132 moveTypeImage =
QImage(
"://icons/general/cursor-diagonal-right.svg");
135 case CameraMoveType::ROTATION:
137 moveTypeImage =
QImage(
"://icons/general/cursor-rotate.svg");
140 case CameraMoveType::PATH:
141 case CameraMoveType::CENTER:
143 moveTypeImage =
QImage(
"://icons/general/cursor-move.svg");
155 rotT.
rotate(mCurrentAngle);
157 cursorPainter.setTransform(rotT);
158 cursorPainter.drawImage(offset, moveTypeImage);
164void CameraTool::updateMoveMode(
const QPointF& pos)
167 if (mScribbleArea->isPointerInUse()) {
172 Layer* layer = mEditor->layers()->currentLayer();
173 mCamMoveMode = CameraMoveType::NONE;
174 qreal selectionTolerance = mEditor->select()->selectionTolerance();
176 Q_ASSERT(layer->type() == Layer::CAMERA);
178 if (layer->keyExists(mEditor->currentFrame()))
180 mCamMoveMode = getCameraMoveMode(pos,
182 }
else if (properties.cameraShowPath) {
183 int keyPos = cam->firstKeyFramePosition();
184 while (keyPos <= cam->getMaxKeyFramePosition())
186 mCamMoveMode = getPathMoveMode(cam,
190 if (mCamMoveMode != CameraMoveType::NONE)
192 mDragPathFrame = keyPos;
196 if (keyPos == cam->getNextKeyFramePosition(keyPos)) {
200 keyPos = cam->getNextKeyFramePosition(keyPos);
205void CameraTool::setShowCameraPath(
const bool showCameraPath)
209 Q_ASSERT(layer->type() == Layer::CAMERA);
210 layer->setShowCameraPath(showCameraPath);
212 properties.cameraShowPath = showCameraPath;
215void CameraTool::setPathDotColorType(
const DotColorType pathDotColor)
218 Q_ASSERT(layer->type() == Layer::CAMERA);
220 layer->updateDotColor(pathDotColor);
223void CameraTool::resetCameraPath()
226 Q_ASSERT(layer->type() == Layer::CAMERA);
228 layer->setPathMovedAtFrame(mEditor->currentFrame(),
false);
232void CameraTool::resetTransform(CameraFieldOption option)
235 Q_ASSERT(layer->type() == Layer::CAMERA);
237 if (option == CameraFieldOption::RESET_ROTATION || option == CameraFieldOption::RESET_FIELD) {
241 layer->resetCameraAtFrame(option, mEditor->currentFrame());
247 Q_ASSERT(editor()->layers()->currentLayer()->type() == Layer::CAMERA);
251 if (mCamMoveMode == CameraMoveType::ROTATION) {
252 angleDeg = getAngleBetween(pos, mCameraRect.
center()) - mStartAngle;
254 angleDeg = constrainedRotation(angleDeg, mRotationIncrement);
256 mCurrentAngle = angleDeg;
259 transformView(layer, mCamMoveMode, pos, mTransformOffset, -angleDeg, mEditor->currentFrame());
262 mTransformOffset = pos;
265void CameraTool::transformCameraPath(
const QPointF& pos)
267 Q_ASSERT(editor()->layers()->currentLayer()->type() == Layer::CAMERA);
270 layer->updatePathControlPointAtFrame(pos, mDragPathFrame);
274int CameraTool::constrainedRotation(
const qreal rotatedAngle,
const int rotationIncrement)
const
276 return qRound(rotatedAngle / rotationIncrement) * rotationIncrement;
281 updateMoveMode(
event->canvasPos());
282 updateUIAssists(mEditor->layers()->currentLayer());
284 mStartAngle = getAngleBetween(
event->canvasPos(), mCameraRect.
center()) - mCurrentAngle;
285 mTransformOffset =
event->canvasPos();
290 Layer* currentLayer = mEditor->layers()->currentLayer();
291 updateMoveMode(
event->canvasPos());
292 updateUIAssists(currentLayer);
294 if (mScribbleArea->isPointerInUse())
296 if (currentLayer->keyExists(mEditor->currentFrame())) {
297 transformCamera(
event->canvasPos(),
event->modifiers());
299 else if (mCamMoveMode == CameraMoveType::PATH)
301 transformCameraPath(
event->canvasPos());
304 mScribbleArea->updateToolCursor();
305 mEditor->view()->forceUpdateViewTransform();
309void CameraTool::pointerReleaseEvent(
PointerEvent* event)
311 Layer* layer = editor()->layers()->currentLayer();
312 updateMoveMode(
event->canvasPos());
313 updateUIAssists(layer);
315 int frame = mEditor->currentFrame();
316 if (layer->keyExists(frame)) {
317 transformCamera(
event->canvasPos(),
event->modifiers());
318 mEditor->view()->forceUpdateViewTransform();
319 }
else if (mCamMoveMode == CameraMoveType::PATH) {
320 transformCameraPath(
event->canvasPos());
321 mEditor->view()->forceUpdateViewTransform();
326qreal CameraTool::getAngleBetween(
const QPointF& pos1,
const QPointF& pos2)
const
328 return qRadiansToDegrees(MathUtils::getDifferenceAngle(pos1, pos2));
331CameraMoveType CameraTool::getCameraMoveMode(
const QPointF& point, qreal tolerance)
const
335 if (camPoly.
count() <= 0) {
return CameraMoveType::NONE; }
339 return CameraMoveType::TOPLEFT;
343 return CameraMoveType::TOPRIGHT;
347 return CameraMoveType::BOTTOMRIGHT;
351 return CameraMoveType::BOTTOMLEFT;
353 else if (
QLineF(point, mRotationHandlePoint).length() < tolerance)
355 return CameraMoveType::ROTATION;
359 return CameraMoveType::CENTER;
361 return CameraMoveType::NONE;
364CameraMoveType CameraTool::getPathMoveMode(
const LayerCamera* layerCamera,
int frameNumber,
const QPointF& point, qreal tolerance)
const
366 int prev = layerCamera->getPreviousKeyFramePosition(frameNumber);
367 int next = layerCamera->getNextKeyFramePosition(frameNumber);
368 if (layerCamera->hasSameTranslation(prev, next))
369 return CameraMoveType::NONE;
371 Camera* camera = layerCamera->getLastCameraAtFrame(frameNumber, 0);
373 if (camera ==
nullptr) {
return CameraMoveType::NONE; }
375 QPointF pathPoint = camera->getPathControlPoint();
377 if (!camera->pathControlPointMoved()) {
378 pathPoint = layerCamera->getCenteredPathPoint(frameNumber);
381 if (
QLineF(pathPoint, point).length() < tolerance) {
382 return CameraMoveType::PATH;
384 return CameraMoveType::NONE;
388QPointF CameraTool::localRotationHandlePoint(
const QPoint& origin,
const QTransform& localT,
const qreal objectScale,
float worldScale)
const
392 qreal topDis = origin.
y() + ((objectScale * origin.
y()) * mRotationHandleOffsetPercentage) * worldScale;
396QPointF CameraTool::worldRotationHandlePoint(
const QPoint& origin,
const QTransform& localT,
const qreal objectScale,
const QTransform& worldT,
float worldScale)
const
398 return worldT.
map(localRotationHandlePoint(origin, localT, objectScale, worldScale));
401void CameraTool::transformView(
LayerCamera* layerCamera, CameraMoveType mode,
const QPointF& point,
const QPointF& offset, qreal angle,
int frameNumber)
const
405 QLineF lineOld(curCenter, point);
406 QLineF lineNew(curCenter, point);
407 Camera* curCam = layerCamera->getCameraAtFrame(frameNumber);
411 case CameraMoveType::CENTER: {
412 curCam->translate(curCam->translation() - (point - offset));
415 case CameraMoveType::TOPLEFT:
416 lineOld.setP2(curPoly.
at(0));
417 curCam->scale(curCam->scaling() * (lineOld.length() / lineNew.length()));
419 case CameraMoveType::TOPRIGHT:
420 lineOld.setP2(curPoly.
at(1));
421 curCam->scale(curCam->scaling() * (lineOld.length() / lineNew.length()));
423 case CameraMoveType::BOTTOMRIGHT:
424 lineOld.setP2(curPoly.
at(2));
425 curCam->scale(curCam->scaling() * (lineOld.length() / lineNew.length()));
427 case CameraMoveType::BOTTOMLEFT:
428 lineOld.setP2(curPoly.
at(3));
429 curCam->scale(curCam->scaling() * (lineOld.length() / lineNew.length()));
431 case CameraMoveType::ROTATION:
432 curCam->rotate(angle);
437 curCam->updateViewTransform();
438 curCam->modification();
443 int frameIndex = mEditor->currentFrame();
444 LayerCamera* cameraLayerBelow =
static_cast<LayerCamera*
>(mEditor->object()->getLayerBelow(mEditor->currentLayerIndex(), Layer::CAMERA));
446 const QTransform& camTransform = cameraLayerBelow->getViewAtFrame(frameIndex);
447 const QRect& cameraRect = cameraLayerBelow->getViewRect();
448 const QTransform& worldT = mEditor->view()->getView();
450 bool isPlaying = mEditor->playback()->isPlaying();
455 int frame = cameraLayerBelow->getPreviousKeyFramePosition(frameIndex);
456 Camera* cam = cameraLayerBelow->getLastCameraAtFrame(qMax(frame, frameIndex), 0);
458 qreal scale = cam->scaling();
459 qreal rotation = cam->rotation();
460 QPointF translation = cam->translation();
461 paintHandles(painter, worldT, camTransform, cameraRect, translation, scale, rotation, !cameraLayerBelow->keyExists(frameIndex));
464 cameraLayerBelow->foreachKeyFrame([&] (
const KeyFrame* keyframe) {
465 paintInterpolations(painter, worldT, frameIndex, cameraLayerBelow,
static_cast<const Camera*
>(keyframe), isPlaying);
470void 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
485 const QPolygonF& camPolygon = Transform::mapToWorldPolygon(camTransform, worldTransform, cameraRect);
491 scaleT.
translate(translation.
x(), translation.
y());
493 const QPolygonF& nonScaledCamPoly = Transform::mapToWorldPolygon(scaleT, worldTransform, cameraRect);
498 painter.
setPen(mHandleDisabledColor);
501 painter.
setPen(mHandlePen);
504 int handleW = mHandleWidth;
505 int radius = handleW / 2;
507 const QRectF& topRightCorner =
QRectF(camPolygon.
at(1).x() - radius,
508 camPolygon.
at(1).y() - radius,
512 const QRectF& bottomRightCorner =
QRectF(camPolygon.
at(2).x() - radius,
513 camPolygon.
at(2).y() - radius,
515 painter.
drawRect(bottomRightCorner);
516 const QRectF& topLeftCorner =
QRectF(camPolygon.
at(0).x() - radius,
517 camPolygon.
at(0).y() - radius,
521 const QRectF& bottomLeftCorner =
QRectF(camPolygon.
at(3).x() - radius,
522 camPolygon.
at(3).y() - radius,
528 const QPointF& rotationHandle = worldRotationHandlePoint(cameraRect.
topLeft(), camTransform, scale, worldTransform, mEditor->viewScaleInversed());
530 painter.
drawLine(topCenter, rotationHandle);
533 (rotationHandle.
y() - handleW*0.5),
539void CameraTool::paintInterpolations(
QPainter& painter,
const QTransform& worldTransform,
int currentFrame,
const LayerCamera* cameraLayer,
const Camera* keyframe,
bool isPlaying)
const
541 QColor cameraDotColor = cameraLayer->getDotColor();
542 int frame = keyframe->pos();
543 int nextFrame = cameraLayer->getNextKeyFramePosition(frame);
545 if (cameraLayer->getShowCameraPath() && !cameraLayer->hasSameTranslation(frame, nextFrame)) {
554 const QRect& cameraRect = cameraLayer->getViewRect();
555 const QTransform& cameraTransform = cameraLayer->getViewAtFrame(currentFrame);
556 const QPointF& centerDot = Transform::mapToWorldRect(cameraTransform, worldTransform, cameraRect).
center();
557 painter.
drawEllipse(centerDot, mDotWidth/2., mDotWidth/2.);
560 if (!keyframe->pathControlPointMoved()) {
561 cameraPathPoint = worldTransform.
map(cameraLayer->getCenteredPathPoint(frame + 1));
563 cameraPathPoint = worldTransform.
map(cameraLayer->getPathControlPointAtFrame(frame + 1));
567 QColor color = cameraDotColor;
568 if (currentFrame > frame && currentFrame < nextFrame)
575 for (
int frameInBetween = frame; frameInBetween <= nextFrame ; frameInBetween++)
577 const QTransform& transform = cameraLayer->getViewAtFrame(frameInBetween);
578 const QPointF&
center = Transform::mapToWorldRect(transform, worldTransform, cameraRect).
center();
579 painter.
drawEllipse(center, mDotWidth/2., mDotWidth/2.);
583 int distance = nextFrame - frame;
585 if (distance >= 2 && !isPlaying) {
586 paintControlPoint(painter, worldTransform, cameraLayer, frame, cameraPathPoint, cameraLayer->keyExists(currentFrame));
593void CameraTool::paintControlPoint(
QPainter& painter,
const QTransform& worldTransform,
const LayerCamera* cameraLayer,
const int frameIndex,
const QPointF& pathPoint,
bool hollowHandle)
const
598 const QList<QPointF>& points = cameraLayer->getBezierPointsAtFrame(frameIndex + 1);
602 Q_ASSERT(points.
size() == 3);
617 const QString& pathType = cameraLayer->getInterpolationTextAtFrame(frameIndex);
625 painter.
setPen(mHandleTextColor);
628 painter.
setPen(mHandleDisabledColor);
631 painter.
setPen(mHandlePen);
634 painter.
drawRect(
static_cast<int>(pathPoint.
x() - mHandleWidth/2),
635 static_cast<int>(pathPoint.
y() - mHandleWidth/2),
636 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...
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