Zoom bar: scroll with cursor position, various usability fixes

Related to #651
parent 2160ead1
Pipeline #26569 passed with stage
in 13 minutes and 19 seconds
......@@ -642,20 +642,6 @@ void GLWidget::slotZoom(bool zoomIn)
}
}
void GLWidget::wheelEvent(QWheelEvent *event)
{
if (((event->modifiers() & Qt::ControlModifier) != 0u) && ((event->modifiers() & Qt::ShiftModifier) != 0u)) {
slotZoom(event->delta() > 0);
return;
}
if ((event->modifiers() & Qt::ControlModifier) != 0u) {
QQuickView::wheelEvent(event);
return;
}
emit mouseSeek(event->delta(), (uint)event->modifiers());
event->accept();
}
void GLWidget::requestSeek(int position)
{
m_consumer->set("scrub_audio", 1);
......
......@@ -147,7 +147,6 @@ public:
protected:
void mouseReleaseEvent(QMouseEvent *event) override;
void mouseDoubleClickEvent(QMouseEvent *event) override;
void wheelEvent(QWheelEvent *event) override;
/** @brief Update producer, should ONLY be called from monitor */
int setProducer(const std::shared_ptr<Mlt::Producer> &producer, bool isActive, int position);
int setProducer(const QString &file);
......
......@@ -1028,12 +1028,18 @@ void Monitor::keyPressEvent(QKeyEvent *event)
void Monitor::slotMouseSeek(int eventDelta, uint modifiers)
{
if ((modifiers & Qt::ShiftModifier) != 0u) {
if ((modifiers & Qt::ControlModifier) != 0u) {
// Shift + Ctrl wheel zooms monitor
m_glMonitor->slotZoom(eventDelta > 0);
return;
}
// Shift wheel seeks one second
int delta = qRound(pCore->getCurrentFps());
if (eventDelta > 0) {
delta = 0 - delta;
delta = -delta;
}
delta = qMax(0, m_glMonitor->getCurrentPos() - delta);
m_glMonitor->getControllerProxy()->setPosition(qMin(delta, m_glMonitor->duration() - 1));
delta = qBound(0, m_glMonitor->getCurrentPos() + delta, m_glMonitor->duration() - 1);
m_glMonitor->getControllerProxy()->setPosition(delta);
} else if ((modifiers & Qt::AltModifier) != 0u) {
if (eventDelta >= 0) {
emit seekToPreviousSnap();
......
......@@ -55,6 +55,11 @@ int MonitorProxy::rulerHeight() const
return q->m_rulerHeight;
}
void MonitorProxy::seek(int delta, uint modifiers)
{
q->mouseSeek(delta, modifiers);
}
int MonitorProxy::overlayType() const
{
return (q->m_id == (int)Kdenlive::ClipMonitor ? KdenliveSettings::clipMonitorOverlayGuides() : KdenliveSettings::projectMonitorOverlayGuides());
......
......@@ -71,6 +71,7 @@ public:
* */
int getPosition() const;
Q_INVOKABLE bool setPosition(int pos);
Q_INVOKABLE void seek(int delta, uint modifiers);
void positionFromConsumer(int pos, bool playing);
void setMarkerComment(const QString &comment);
int zoneIn() const;
......
......@@ -12,11 +12,55 @@ Rectangle {
property double rulerZoomWidth: root.zoomFactor * width
// The pixel offset
property double rulerZoomOffset: root.zoomStart * width / root.zoomFactor
property int playheadPosition: controller.position
Rectangle {
color: activePalette.light
width: parent.width
height: 1
}
Timer {
id: scrollTimer
interval: 200; running: false;
onTriggered: {
if (rulerMouseArea.pressed) {
// Check if seeking ruler
var pos = Math.max(rulerMouseArea.mouseX, 0)
root.mouseRulerPos = pos
controller.position = Math.min((pos + ruler.rulerZoomOffset) / root.timeScale, root.duration);
} else if (root.showAudiothumb) {
// Check if seeking audio thumbnail zone
root.updateScrolling()
}
}
}
onPlayheadPositionChanged: {
if (root.zoomFactor == 1) {
return
}
var scaledPosition = ruler.playheadPosition * root.timeScale - ruler.rulerZoomOffset
if (scaledPosition < root.baseUnit) {
if (scaledPosition < 0) {
zoomBar.x = Math.max(0, zoomBar.x + (scaledPosition * root.zoomFactor ) - (zoomBar.width / 2))
root.zoomStart = zoomBar.x / zoomHandleContainer.width
} else {
zoomBar.x = Math.max(0, zoomBar.x - root.baseUnit * root.zoomFactor)
root.zoomStart = zoomBar.x / zoomHandleContainer.width
scrollTimer.start()
}
} else if (scaledPosition > zoomHandleContainer.width - root.baseUnit) {
if (scaledPosition > zoomHandleContainer.width) {
zoomBar.x = Math.min(zoomHandleContainer.width - zoomBar.width, zoomBar.x + (scaledPosition * root.zoomFactor) - (zoomBar.width / 2))
root.zoomStart = zoomBar.x / zoomHandleContainer.width
} else {
zoomBar.x = Math.min(zoomHandleContainer.width - zoomBar.width, zoomBar.x + root.baseUnit * root.zoomFactor)
root.zoomStart = zoomBar.x / zoomHandleContainer.width
scrollTimer.start()
}
}
}
function zoomInRuler(xPos)
{
......@@ -71,6 +115,29 @@ Rectangle {
right: parent.right
bottom: parent.top
}
MouseArea {
anchors.fill: parent
onWheel: {
if (wheel.modifiers & Qt.ControlModifier) {
if (wheel.angleDelta.y < 0) {
// zoom out
zoomOutRuler(wheel.x)
} else {
// zoom in
zoomInRuler(wheel.x)
}
} else {
if (wheel.angleDelta.y < 0) {
var newPos = Math.min(zoomHandleContainer.width - zoomBar.width, zoomBar.x + 10)
zoomBar.x = newPos
} else {
var newPos = Math.max(0, zoomBar.x - 10)
zoomBar.x = newPos
}
root.zoomStart = zoomBar.x / zoomHandleContainer.width
}
}
}
Item {
id: zoomHandleContainer
property int previousX: 0
......@@ -113,6 +180,7 @@ Rectangle {
}
}
onWheel: {
console.log('GOT ZOOM WHEEL OK')
if (wheel.modifiers & Qt.ControlModifier) {
if (wheel.angleDelta.y < 0) {
// zoom out
......@@ -121,6 +189,15 @@ Rectangle {
// zoom in
zoomInRuler(wheel.x)
}
} else {
if (wheel.angleDelta.y < 0) {
var newPos = Math.min(zoomHandleContainer.width - zoomBar.width, zoomBar.x + 10)
zoomBar.x = newPos
} else {
var newPos = Math.max(0, zoomBar.x - 10)
zoomBar.x = newPos
}
root.zoomStart = zoomBar.x / zoomHandleContainer.width
}
}
}
......@@ -277,6 +354,7 @@ Rectangle {
MouseArea {
id: rulerMouseArea
anchors.fill: parent
propagateComposedEvents: true
hoverEnabled: true
onPressed: {
if (mouse.buttons === Qt.LeftButton) {
......@@ -302,6 +380,8 @@ Rectangle {
// zoom in
zoomInRuler(wheel.x)
}
} else {
wheel.accepted = false
}
}
}
......@@ -350,7 +430,7 @@ Rectangle {
opacity: 1
anchors.top: ruler.top
fillColor: activePalette.windowText
x: controller.position * root.timeScale - (width / 2) - ruler.rulerZoomOffset
x: controller.position * root.timeScale - ruler.rulerZoomOffset - (width / 2)
}
Rectangle {
id: trimIn
......
......@@ -44,6 +44,7 @@ Item {
property color overlayColor: 'cyan'
property bool isClipMonitor: true
property int dragType: 0
property int overlayMargin: (audioThumb.stateVisible && !audioThumb.isAudioClip && audioThumb.visible) ? (audioThumb.height + root.zoomOffset) : root.zoomOffset
FontMetrics {
id: fontMetrics
......@@ -57,6 +58,16 @@ Item {
signal editCurrentMarker()
function updateScrolling()
{
if (thumbMouseArea.pressed) {
var pos = Math.max(thumbMouseArea.mouseX, 0)
pos += audioThumb.width/root.zoomFactor * root.zoomStart
controller.setPosition(Math.min(pos / root.timeScale, root.duration));
}
}
onDurationChanged: {
clipMonitorRuler.updateRuler()
// Reset zoom on clip change
......@@ -92,7 +103,11 @@ Item {
hoverEnabled: true
acceptedButtons: Qt.NoButton
anchors.fill: parent
onWheel: {
controller.seek(wheel.angleDelta.x + wheel.angleDelta.y, wheel.modifiers)
}
}
SceneToolBar {
id: sceneToolBar
barContainsMouse: sceneToolBar.rightSide ? barOverArea.mouseX >= x - 10 : barOverArea.mouseX < x + width + 10
......@@ -146,7 +161,7 @@ Item {
Item {
id: audioThumb
property bool stateVisible: (clipMonitorRuler.containsMouse || thumbMouseArea.containsMouse || thumbTimer.running || root.showZoomBar)
property bool stateVisible: (clipMonitorRuler.containsMouse || thumbMouseArea.containsMouse || dragZone.opacity == 1 || thumbTimer.running || root.showZoomBar)
property bool isAudioClip: controller.clipType == ProducerType.Audio
anchors {
left: parent.left
......@@ -236,6 +251,7 @@ Item {
anchors.fill: parent
acceptedButtons: audioThumb.isAudioClip ? Qt.NoButton : Qt.LeftButton
hoverEnabled: true
propagateComposedEvents: true
onPressed: {
var pos = Math.max(mouseX, 0)
pos += audioThumb.width/root.zoomFactor * root.zoomStart
......@@ -257,7 +273,10 @@ Item {
// zoom in
clipMonitorRuler.zoomInRuler(wheel.x)
}
} else {
wheel.accepted = false
}
}
}
}
......@@ -298,7 +317,7 @@ Item {
anchors {
right: parent.right
bottom: parent.bottom
bottomMargin: (audioThumb.stateVisible && !audioThumb.isAudioClip && audioThumb.visible) ? (audioThumb.height + root.zoomOffset) : root.zoomOffset
bottomMargin: overlayMargin
}
}
Label {
......@@ -316,7 +335,7 @@ Item {
anchors {
right: timecode.visible ? timecode.left : parent.right
bottom: parent.bottom
bottomMargin: (audioThumb.stateVisible && !audioThumb.isAudioClip && audioThumb.visible) ? (audioThumb.height + root.zoomOffset) : root.zoomOffset
bottomMargin: overlayMargin
}
}
Label {
......@@ -325,7 +344,7 @@ Item {
anchors {
left: parent.left
bottom: parent.bottom
bottomMargin: root.zoomOffset
bottomMargin: overlayMargin
}
visible: root.showMarkers && controller.position == controller.zoneIn
text: i18n("In Point")
......@@ -342,7 +361,7 @@ Item {
anchors {
left: inPoint.visible ? inPoint.right : parent.left
bottom: parent.bottom
bottomMargin: root.zoomOffset
bottomMargin: overlayMargin
}
visible: root.showMarkers && controller.position + 1 == controller.zoneOut
text: i18n("Out Point")
......@@ -367,7 +386,7 @@ Item {
anchors {
left: outPoint.visible ? outPoint.right : inPoint.visible ? inPoint.right : parent.left
bottom: parent.bottom
bottomMargin: root.zoomOffset
bottomMargin: overlayMargin
}
visible: root.showMarkers && text != ""
height: inPoint.height
......@@ -384,13 +403,14 @@ Item {
Rectangle {
// Audio or video only drag zone
id: dragZone
x: 2
y: inPoint.visible || outPoint.visible || marker.visible ? parent.height - inPoint.height - height - 2 - root.zoomOffset : parent.height - height - 2 - root.zoomOffset
y: inPoint.visible || outPoint.visible || marker.visible ? parent.height - inPoint.height - height - 2 - overlayMargin : parent.height - height - 2 - overlayMargin
width: childrenRect.width
height: childrenRect.height
color: Qt.rgba(activePalette.highlight.r, activePalette.highlight.g, activePalette.highlight.b, 0.7)
radius: 4
opacity: (dragAudioArea.containsMouse || dragVideoArea.containsMouse || thumbMouseArea.containsMouse || (barOverArea.containsMouse && barOverArea.mouseY >= y)) ? 1 : 0
opacity: (dragAudioArea.containsMouse || dragVideoArea.containsMouse || thumbMouseArea.containsMouse || (barOverArea.containsMouse && (barOverArea.mouseY >= (parent.height - inPoint.height - height - 2 - (audioThumb.height + root.zoomOffset) - root.baseUnit)))) ? 1 : 0
visible: controller.clipHasAV
onOpacityChanged: {
if (opacity == 1) {
......
......@@ -68,6 +68,9 @@ Item {
hoverEnabled: true
acceptedButtons: Qt.NoButton
anchors.fill: parent
onWheel: {
controller.seek(wheel.angleDelta.x + wheel.angleDelta.y, wheel.modifiers)
}
}
SceneToolBar {
id: sceneToolBar
......
......@@ -187,7 +187,9 @@ Item {
anchors.centerIn: root
hoverEnabled: true
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onWheel: {
controller.seek(wheel.angleDelta.x + wheel.angleDelta.y, wheel.modifiers)
}
onDoubleClicked: {
controller.addRemoveKeyframe()
}
......
......@@ -189,6 +189,9 @@ Item {
hoverEnabled: true
acceptedButtons: Qt.LeftButton | Qt.RightButton
cursorShape: containsMouse ? Qt.PointingHandCursor : Qt.ArrowCursor
onWheel: {
controller.seek(wheel.angleDelta.x + wheel.angleDelta.y, wheel.modifiers)
}
readonly property bool containsMouse: {
if (isMoving) {
......
......@@ -360,7 +360,9 @@ Item {
property bool centerContainsMouse
hoverEnabled: true
cursorShape: (!root.isDefined || pointContainsMouse || centerContainsMouse || addedPointIndex >= 0 || resizeContainsMouse > 0 ) ? Qt.PointingHandCursor : Qt.ArrowCursor
onWheel: {
controller.seek(wheel.angleDelta.x + wheel.angleDelta.y, wheel.modifiers)
}
onDoubleClicked: {
if (root.isDefined) {
if (root.displayResize) {
......
......@@ -52,6 +52,9 @@ Item {
hoverEnabled: true
cursorShape: Qt.SizeHorCursor
acceptedButtons: Qt.LeftButton
onWheel: {
controller.seek(wheel.angleDelta.x + wheel.angleDelta.y, wheel.modifiers)
}
onPressed: {
root.percentage = (mouseX - (root.width - (root.profile.x * root.scalex)) / 2) / (root.profile.x * root.scalex)
root.splitterPos = mouseX
......
......@@ -55,6 +55,9 @@ Item {
hoverEnabled: true
acceptedButtons: Qt.NoButton
anchors.fill: parent
onWheel: {
controller.seek(wheel.angleDelta.x + wheel.angleDelta.y, wheel.modifiers)
}
}
Item {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment