/*** Olive - Non-Linear Video Editor Copyright (C) 2022 Olive Team Modifications Copyright (C) 2025 mikesolar This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ***/ #include "handmovableview.h" #include #include "config/config.h" #include "core.h" namespace olive { #define super QGraphicsView HandMovableView::HandMovableView(QWidget *parent) : super(parent) , dragging_hand_(false) , default_drag_mode_(NoDrag) , is_timeline_axes_(false) { connect(Core::instance(), &Core::ToolChanged, this, &HandMovableView::ApplicationToolChanged); } void HandMovableView::ApplicationToolChanged(Tool::Item tool) { if (tool == Tool::kHand) { setDragMode(ScrollHandDrag); setInteractive(false); } else { setDragMode(default_drag_mode_); setInteractive(true); } ToolChangedEvent(tool); } bool HandMovableView::HandPress(QMouseEvent *event) { if (event->button() == Qt::MiddleButton) { pre_hand_drag_mode_ = dragMode(); dragging_hand_ = true; setDragMode(ScrollHandDrag); setInteractive(false); // Transform mouse event to act like the left button is pressed QMouseEvent transformed(event->type(), event->pos(), Qt::LeftButton, Qt::LeftButton, event->modifiers()); transformed_pos_ = QPoint(0, 0); super::mousePressEvent(&transformed); return true; } return false; } bool HandMovableView::HandMove(QMouseEvent *event) { if (dragging_hand_) { // Transform mouse event to act like the left button is pressed QPoint adjustment(0, 0); QMouseEvent transformed(event->type(), event->pos() - transformed_pos_, Qt::LeftButton, Qt::LeftButton, event->modifiers()); if (event->pos().x() < 0) { transformed_pos_.setX(transformed_pos_.x() + width()); adjustment.setX(width()); } else if (event->pos().x() >= width()) { transformed_pos_.setX(transformed_pos_.x() - width()); adjustment.setX(-width()); } if (event->pos().y() < 0) { transformed_pos_.setY(transformed_pos_.y() + height()); adjustment.setY(height()); } else if (event->pos().y() >= height()) { transformed_pos_.setY(transformed_pos_.y() - height()); adjustment.setY(-height()); } if (!adjustment.isNull()) { QCursor::setPos(QCursor::pos() + adjustment); } super::mouseMoveEvent(&transformed); } return dragging_hand_; } bool HandMovableView::HandRelease(QMouseEvent *event) { if (dragging_hand_) { // Transform mouse event to act like the left button is pressed QMouseEvent transformed(event->type(), event->localPos(), event->windowPos(), event->screenPos(), Qt::LeftButton, Qt::LeftButton, event->modifiers(), event->source()); super::mouseReleaseEvent(&transformed); setInteractive(true); setDragMode(pre_hand_drag_mode_); dragging_hand_ = false; return true; } return false; } void HandMovableView::SetDefaultDragMode(HandMovableView::DragMode mode) { default_drag_mode_ = mode; setDragMode(default_drag_mode_); } const HandMovableView::DragMode &HandMovableView::GetDefaultDragMode() const { return default_drag_mode_; } bool HandMovableView::WheelEventIsAZoomEvent(QWheelEvent *event) { return (static_cast(event->modifiers() & Qt::ControlModifier) == !OLIVE_CONFIG("ScrollZooms").toBool()); } qreal HandMovableView::GetScrollZoomMultiplier(QWheelEvent *event) { qreal v = (static_cast(event->angleDelta().x() + event->angleDelta().y()) * 0.001); if (event->inverted()) { v = -v; } return 1.0 + v; } void HandMovableView::wheelEvent(QWheelEvent *event) { if (WheelEventIsAZoomEvent(event)) { if (!event->angleDelta().isNull()) { qreal multiplier = GetScrollZoomMultiplier(event); QPointF cursor_pos; #if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) cursor_pos = event->position(); #else cursor_pos = event->posF(); #endif ZoomIntoCursorPosition(event, multiplier, cursor_pos); } } else if (is_timeline_axes_) { #if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) QPoint angle_delta = event->angleDelta(); if (OLIVE_CONFIG("InvertTimelineScrollAxes") .toBool() // Check if config is set to invert timeline axes && event->source() != Qt::MouseEventSynthesizedBySystem) { // Never flip axes on Apple trackpads though angle_delta = QPoint(angle_delta.y(), angle_delta.x()); } QWheelEvent e( #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) event->position(), event->globalPosition(), #else event->pos(), event->globalPos(), #endif event->pixelDelta(), angle_delta, event->buttons(), event->modifiers(), event->phase(), event->inverted(), event->source()); #else Qt::Orientation orientation = event->orientation(); if (OLIVE_CONFIG("InvertTimelineScrollAxes").toBool()) { orientation = (orientation == Qt::Horizontal) ? Qt::Vertical : Qt::Horizontal; } QWheelEvent e(event->pos(), event->globalPos(), event->pixelDelta(), event->angleDelta(), event->delta(), orientation, event->buttons(), event->modifiers()); #endif super::wheelEvent(&e); } else { super::wheelEvent(event); } } void HandMovableView::ZoomIntoCursorPosition(QWheelEvent *event, double multiplier, const QPointF &cursor_pos) { Q_UNUSED(event) Q_UNUSED(multiplier) Q_UNUSED(cursor_pos) } }