From d7cb00d10c3b79c99030fee8ba7a9e21a0595960 Mon Sep 17 00:00:00 2001
From: Ulf Hermann <ulf.hermann@digia.com>
Date: Wed, 13 Nov 2013 12:10:48 +0100
Subject: [PATCH] QmlProfiler: Fix jaggy behavior of range start handle

The left handle of the range mover element didn't properly follow
the mouse movement. Also, a lot of code is duplicated between
RangeMover and SelectionRange. This change prepares RangeMover for
being reused in SelectionRange by eliminating external
dependencies.

Task-number: QTCREATORBUG-10762
Change-Id: Ia3b83101263e7af8ed46e1aaf4e92654b0068861
Reviewed-by: Kai Koehne <kai.koehne@digia.com>
---
 src/plugins/qmlprofiler/qml/Overview.qml   |  42 +++++---
 src/plugins/qmlprofiler/qml/RangeMover.qml | 117 ++++++++++-----------
 2 files changed, 83 insertions(+), 76 deletions(-)

diff --git a/src/plugins/qmlprofiler/qml/Overview.qml b/src/plugins/qmlprofiler/qml/Overview.qml
index a1b54369cd7..7d0916787da 100644
--- a/src/plugins/qmlprofiler/qml/Overview.qml
+++ b/src/plugins/qmlprofiler/qml/Overview.qml
@@ -49,12 +49,15 @@ Canvas2D {
     }
 
     function updateRange() {
-        var newStartTime = Math.round(rangeMover.x * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
-        var newEndTime = Math.round((rangeMover.x + rangeMover.width) * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
+        var newStartTime = Math.round(rangeMover.getLeft() * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
+        var newEndTime = Math.round(rangeMover.getRight() * qmlProfilerModelProxy.traceDuration() / width) + qmlProfilerModelProxy.traceStartTime();
         if (startTime !== newStartTime || endTime !== newEndTime) {
             zoomControl.setRange(newStartTime, newEndTime);
         }
+    }
 
+    function clamp(val, min, max) {
+        return Math.min(Math.max(val, min), max);
     }
 
     // ***** connections to external objects
@@ -62,14 +65,17 @@ Canvas2D {
         target: zoomControl
         onRangeChanged: {
             if (qmlProfilerModelProxy) {
-                startTime = zoomControl.startTime();
-                endTime = zoomControl.endTime();
+                startTime = clamp(zoomControl.startTime(), qmlProfilerModelProxy.traceStartTime(), qmlProfilerModelProxy.traceEndTime());
+                endTime = clamp(zoomControl.endTime(), startTime, qmlProfilerModelProxy.traceEndTime());
                 var newRangeX = (startTime - qmlProfilerModelProxy.traceStartTime()) * width / qmlProfilerModelProxy.traceDuration();
-                if (rangeMover.x !== newRangeX)
-                    rangeMover.x = newRangeX;
-                var newWidth = (endTime-startTime) * width / qmlProfilerModelProxy.traceDuration();
-                if (rangeMover.width !== newWidth)
-                    rangeMover.width = newWidth;
+                var newWidth = (endTime - startTime) * width / qmlProfilerModelProxy.traceDuration();
+                var widthChanged = Math.abs(newWidth - rangeMover.getWidth()) > 1;
+                var leftChanged = Math.abs(newRangeX - rangeMover.getLeft()) > 1;
+                if (leftChanged)
+                    rangeMover.setLeft(newRangeX);
+
+                if (leftChanged || widthChanged)
+                    rangeMover.setRight(newRangeX + newWidth);
             }
         }
     }
@@ -97,13 +103,20 @@ Canvas2D {
     MouseArea {
         anchors.fill: canvas
         function jumpTo(posX) {
-            var newX = posX - rangeMover.width/2;
+            var rangeWidth = rangeMover.getWidth();
+            var newX = posX - rangeWidth / 2;
             if (newX < 0)
                 newX = 0;
-            if (newX + rangeMover.width > canvas.width)
-                newX = canvas.width - rangeMover.width;
-            rangeMover.x = newX;
-            updateRange();
+            if (newX + rangeWidth > canvas.width)
+                newX = canvas.width - rangeWidth;
+
+            if (newX < rangeMover.getLeft()) {
+                rangeMover.setLeft(newX);
+                rangeMover.setRight(newX + rangeWidth);
+            } else if (newX > rangeMover.getLeft()) {
+                rangeMover.setRight(newX + rangeWidth);
+                rangeMover.setLeft(newX);
+            }
         }
 
         onPressed: {
@@ -117,6 +130,7 @@ Canvas2D {
     RangeMover {
         id: rangeMover
         visible: dataReady
+        onRangeChanged: canvas.updateRange()
     }
 
     Rectangle {
diff --git a/src/plugins/qmlprofiler/qml/RangeMover.qml b/src/plugins/qmlprofiler/qml/RangeMover.qml
index 5c786153db8..157fffcc44e 100644
--- a/src/plugins/qmlprofiler/qml/RangeMover.qml
+++ b/src/plugins/qmlprofiler/qml/RangeMover.qml
@@ -31,41 +31,46 @@ import QtQuick 2.1
 
 Rectangle {
     id: rangeMover
+    anchors.fill: parent
+    color: "transparent"
+    signal rangeChanged()
+    signal rangeDoubleClicked()
 
-
+    property color handleColor: "#869cd1"
     property color rangeColor:"#444a64b8"
+    property color dragColor:"#664a64b8"
     property color borderColor:"#cc4a64b8"
     property color dragMarkerColor: "#4a64b8"
-    width: 20
-    height: 50
+    property color singleLineColor: "#4a64b8"
 
-    color: rangeColor
+    function setLeft(left) { leftRange.x = left }
+    function getLeft() { return leftRange.x }
 
-    property bool dragStarted: false
-    onXChanged: {
-        if (dragStarted) canvas.updateRange()
-    }
+    function setRight(right) { rightRange.x = right }
+    function getRight() { return rightRange.x }
 
-    MouseArea {
-        anchors.fill: parent
-        drag.target: rangeMover
-        drag.axis: "XAxis"
-        drag.minimumX: 0
-        drag.maximumX: canvas.width - rangeMover.width
-        onPressed: {
-            parent.dragStarted = true;
-        }
-        onReleased: {
-            parent.dragStarted = false;
-        }
+    function getWidth() { return rightRange.x - leftRange.x }
+
+    Rectangle {
+        id: selectedRange
+
+        x: leftRange.x
+        width: rightRange.x - leftRange.x
+        height: parent.height
+
+        color: width > 1 ? (dragArea.pressed ? dragColor : rangeColor) : singleLineColor
+
+        onXChanged: parent.rangeChanged()
+        onWidthChanged: parent.rangeChanged()
     }
 
     Rectangle {
         id: leftRange
 
-        // used for dragging the borders
-        property real initialX: 0
-        property real initialWidth: 0
+        onXChanged: {
+            if (dragArea.drag.active)
+                rightRange.x = x + dragArea.origWidth;
+        }
 
         x: 0
         height: parent.height
@@ -75,9 +80,9 @@ Rectangle {
         Rectangle {
             id: leftBorderHandle
             height: parent.height
-            x: -width
+            anchors.right: parent.left
             width: 7
-            color: "#869cd1"
+            color: handleColor
             visible: false
             Image {
                 source: "range_handle.png"
@@ -85,7 +90,7 @@ Rectangle {
                 width: 4
                 height: 9
                 fillMode: Image.Tile
-                y: rangeMover.height / 2 - 4
+                y: parent.height / 2 - 4
             }
         }
 
@@ -97,25 +102,14 @@ Rectangle {
             }
         }
 
-        onXChanged: {
-            if (x !== 0) {
-                rangeMover.width = initialWidth - x;
-                rangeMover.x = initialX + x;
-                x = 0;
-                canvas.updateRange();
-            }
-        }
-
         MouseArea {
-            x: -10
-            width: 13
-            y: 0
-            height: parent.height
+            anchors.fill: leftBorderHandle
 
             drag.target: leftRange
             drag.axis: "XAxis"
-            drag.minimumX: -parent.initialX
-            drag.maximumX: parent.initialWidth - 2
+            drag.minimumX: 0
+            drag.maximumX: rangeMover.width
+            drag.onActiveChanged: drag.maximumX = rightRange.x
 
             hoverEnabled: true
 
@@ -128,17 +122,13 @@ Rectangle {
             onReleased: {
                 if (!containsMouse) parent.state = "";
             }
-            onPressed: {
-                parent.initialX = rangeMover.x;
-                parent.initialWidth = rangeMover.width;
-            }
         }
     }
 
     Rectangle {
         id: rightRange
 
-        x: rangeMover.width
+        x: 1
         height: parent.height
         width: 1
         color: borderColor
@@ -146,9 +136,9 @@ Rectangle {
         Rectangle {
             id: rightBorderHandle
             height: parent.height
-            x: 1
+            anchors.left: parent.right
             width: 7
-            color: "#869cd1"
+            color: handleColor
             visible: false
             Image {
                 source: "range_handle.png"
@@ -156,7 +146,7 @@ Rectangle {
                 width: 4
                 height: 9
                 fillMode: Image.Tile
-                y: rangeMover.height / 2 - 4
+                y: parent.height / 2 - 4
             }
         }
 
@@ -168,23 +158,14 @@ Rectangle {
             }
         }
 
-        onXChanged: {
-            if (x!=rangeMover.width) {
-                rangeMover.width = x;
-                canvas.updateRange();
-            }
-        }
-
         MouseArea {
-            x: -3
-            width: 13
-            y: 0
-            height: parent.height
+            anchors.fill: rightBorderHandle
 
             drag.target: rightRange
             drag.axis: "XAxis"
-            drag.minimumX: 1
-            drag.maximumX: canvas.width - rangeMover.x
+            drag.minimumX: 0
+            drag.maximumX: rangeMover.width
+            drag.onActiveChanged: drag.minimumX = leftRange.x
 
             hoverEnabled: true
 
@@ -200,4 +181,16 @@ Rectangle {
         }
     }
 
+    MouseArea {
+        id: dragArea
+        property int origWidth: 0
+
+        anchors.fill: selectedRange
+        drag.target: leftRange
+        drag.axis: "XAxis"
+        drag.minimumX: 0
+        drag.maximumX: rangeMover.width - origWidth
+        drag.onActiveChanged: origWidth = selectedRange.width
+        onDoubleClicked: parent.rangeDoubleClicked()
+    }
 }
-- 
GitLab