From 3cc743f1bf54da047cefc575dac03aa71a0dc88b Mon Sep 17 00:00:00 2001 From: Ulf Hermann <ulf.hermann@digia.com> Date: Thu, 27 Feb 2014 12:14:45 +0100 Subject: [PATCH] QmlProfiler: Provide a horizontal scroll bar for the timeline This requires the consolidation of the nested Flickable elements into one, which is probably a good idea anyway. The horizontal scroll bar is important because people might not understand that they can use the overview for scrolling. Change-Id: Ie1555265fc3edafaf6e6e4f34d77b0d034d45639 Reviewed-by: Kai Koehne <kai.koehne@digia.com> --- src/plugins/qmlprofiler/qml/MainView.qml | 297 +++++++++--------- .../qmlprofiler/qml/SelectionRange.qml | 6 +- src/plugins/qmlprofiler/qml/TimeMarks.qml | 2 +- 3 files changed, 151 insertions(+), 154 deletions(-) diff --git a/src/plugins/qmlprofiler/qml/MainView.qml b/src/plugins/qmlprofiler/qml/MainView.qml index 0f5c805604d..8659e5e8ba8 100644 --- a/src/plugins/qmlprofiler/qml/MainView.qml +++ b/src/plugins/qmlprofiler/qml/MainView.qml @@ -66,6 +66,8 @@ Rectangle { property date recordingStartDate property real elapsedTime + color: "#dcdcdc" + // ***** connections with external objects Connections { target: zoomControl @@ -230,12 +232,51 @@ Rectangle { } Flickable { - id: vertflick + id: labelsflick flickableDirection: Flickable.VerticalFlick - anchors.fill: parent - clip: true + interactive: false + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + width: labels.width + contentY: flick.contentY + + Rectangle { + id: labels + anchors.left: parent.left + width: 150 + color: root.color + height: col.height + + property int rowCount: qmlProfilerModelProxy.categoryCount(); + + Column { + id: col + Repeater { + model: labels.rowCount + delegate: CategoryLabel { } + } + } + } + } + + // border between labels and timeline + Rectangle { + id: labelsborder + anchors.left: labelsflick.right + anchors.top: parent.top + anchors.bottom: parent.bottom + width: 1 + color: "#858585" + } + + Flickable { + id: flick contentHeight: labels.height + contentWidth: 0 + flickableDirection: Flickable.HorizontalAndVerticalFlick boundsBehavior: Flickable.StopAtBounds + clip:true // ScrollView will try to deinteractivate it. We don't want that // as the horizontal flickable is interactive, too. We do occasionally @@ -244,178 +285,136 @@ Rectangle { onInteractiveChanged: interactive = stayInteractive onStayInteractiveChanged: interactive = stayInteractive + function setContentWidth() { + var duration = Math.abs(zoomControl.endTime() - zoomControl.startTime()); + if (duration > 0) + contentWidth = qmlProfilerModelProxy.traceDuration() * width / duration; + } + + onContentXChanged: view.updateZoomControl() + onWidthChanged: setContentWidth() + // ***** child items TimeMarks { id: backgroundMarks - y: vertflick.contentY - height: vertflick.height - width: root.width - labels.width - anchors.left: labels.right + y: flick.contentY + x: flick.contentX + height: flick.height + width: scroller.width } - Flickable { - function setContentWidth() { - var duration = Math.abs(zoomControl.endTime() - zoomControl.startTime()); - if (duration > 0) - contentWidth = qmlProfilerModelProxy.traceDuration() * width / duration; - } - - id: flick - anchors.top: parent.top - anchors.topMargin: labels.y - anchors.right: parent.right - anchors.left: labels.right - contentWidth: 0 - height: labels.height + labelsTail.height - flickableDirection: Flickable.HorizontalFlick - boundsBehavior: Flickable.StopAtBounds - - onContentXChanged: view.updateZoomControl() - onWidthChanged: setContentWidth() - - clip:true - - SelectionRange { - id: selectionRange - visible: root.selectionRangeMode && creationState !== 0 - height: parent.height - z: 2 - } - - TimelineRenderer { - id: view - - profilerModelProxy: qmlProfilerModelProxy - - x: flick.contentX - y: vertflick.contentY - width: flick.width - height: vertflick.height - - onEndTimeChanged: requestPaint() - onYChanged: requestPaint() - onHeightChanged: requestPaint() - - function updateZoomControl() { - var newStartTime = Math.round(flick.contentX * (endTime - startTime) / flick.width) + - qmlProfilerModelProxy.traceStartTime(); - if (Math.abs(newStartTime - startTime) > 1) { - var newEndTime = Math.round((flick.contentX + flick.width) * - (endTime - startTime) / - flick.width) + - qmlProfilerModelProxy.traceStartTime(); - zoomControl.setRange(newStartTime, newEndTime); - } - } - - function updateFlickRange(start, end) { - if (start !== startTime || end !== endTime) { - startTime = start; - endTime = end; - var newStartX = (startTime - qmlProfilerModelProxy.traceStartTime()) * - flick.width / (endTime-startTime); - if (isFinite(newStartX) && Math.abs(newStartX - flick.contentX) >= 1) - flick.contentX = newStartX; - } - } + SelectionRange { + id: selectionRange + visible: root.selectionRangeMode && creationState !== 0 + z: 2 + } - onSelectedItemChanged: { - if (selectedItem !== -1) { - // display details - rangeDetails.showInfo(qmlProfilerModelProxy.getEventDetails(selectedModel, selectedItem)); - rangeDetails.setLocation(qmlProfilerModelProxy.getEventLocation(selectedModel, selectedItem)); + TimelineRenderer { + id: view - // center view (horizontally) - var windowLength = view.endTime - view.startTime; - var eventStartTime = qmlProfilerModelProxy.getStartTime(selectedModel, selectedItem); - var eventEndTime = eventStartTime + - qmlProfilerModelProxy.getDuration(selectedModel, selectedItem); + profilerModelProxy: qmlProfilerModelProxy - if (eventEndTime < view.startTime || eventStartTime > view.endTime) { - var center = (eventStartTime + eventEndTime)/2; - var from = Math.min(qmlProfilerModelProxy.traceEndTime()-windowLength, - Math.max(0, Math.floor(center - windowLength/2))); + x: flick.contentX + y: flick.contentY - zoomControl.setRange(from, from + windowLength); + // paint "under" the vertical scrollbar, so that it always matches with the timemarks + width: scroller.width + height: flick.height - } - } else { - root.hideRangeDetails(); - } - } + onEndTimeChanged: requestPaint() + onYChanged: requestPaint() + onHeightChanged: requestPaint() - onItemPressed: { - var location = qmlProfilerModelProxy.getEventLocation(modelIndex, pressedItem); - if (location.hasOwnProperty("file")) // not empty - root.gotoSourceLocation(location.file, location.line, location.column); + function updateZoomControl() { + var newStartTime = Math.round(flick.contentX * (endTime - startTime) / flick.width) + + qmlProfilerModelProxy.traceStartTime(); + if (Math.abs(newStartTime - startTime) > 1) { + var newEndTime = Math.round((flick.contentX + flick.width) * + (endTime - startTime) / + flick.width) + + qmlProfilerModelProxy.traceStartTime(); + zoomControl.setRange(newStartTime, newEndTime); } - - // hack to pass mouse events to the other mousearea if enabled - startDragArea: selectionRange.ready ? selectionRange.getLeft() : -flick.contentX - endDragArea: selectionRange.ready ? selectionRange.getRight() : -flick.contentX-1 } - MouseArea { - id: selectionRangeControl - enabled: false - width: flick.width - height: flick.height - x: flick.contentX - hoverEnabled: enabled - z: 2 - - onReleased: { - selectionRange.releasedOnCreation(); - } - onPressed: { - selectionRange.pressedOnCreation(); - } - onCanceled: { - selectionRange.releasedOnCreation(); - } - onPositionChanged: { - selectionRange.movedOnCreation(); + + function updateFlickRange(start, end) { + if (start !== startTime || end !== endTime) { + startTime = start; + endTime = end; + var newStartX = (startTime - qmlProfilerModelProxy.traceStartTime()) * + flick.width / (endTime-startTime); + if (isFinite(newStartX) && Math.abs(newStartX - flick.contentX) >= 1) + flick.contentX = newStartX; } } - } - Rectangle { - id: labels - width: 150 - color: "#dcdcdc" - height: col.height + onSelectedItemChanged: { + if (selectedItem !== -1) { + // display details + rangeDetails.showInfo(qmlProfilerModelProxy.getEventDetails(selectedModel, selectedItem)); + rangeDetails.setLocation(qmlProfilerModelProxy.getEventLocation(selectedModel, selectedItem)); - property int rowCount: qmlProfilerModelProxy.categoryCount(); + // center view (horizontally) + var windowLength = view.endTime - view.startTime; + var eventStartTime = qmlProfilerModelProxy.getStartTime(selectedModel, selectedItem); + var eventEndTime = eventStartTime + + qmlProfilerModelProxy.getDuration(selectedModel, selectedItem); - Column { - id: col - Repeater { - model: labels.rowCount - delegate: CategoryLabel { } + if (eventEndTime < view.startTime || eventStartTime > view.endTime) { + var center = (eventStartTime + eventEndTime)/2; + var from = Math.min(qmlProfilerModelProxy.traceEndTime()-windowLength, + Math.max(0, Math.floor(center - windowLength/2))); + + zoomControl.setRange(from, from + windowLength); + + } + } else { + root.hideRangeDetails(); } } - } - Rectangle { - id: labelsTail - anchors.top: labels.bottom - height: Math.max(0, vertflick.height - labels.height) - width: labels.width - color: labels.color - } + onItemPressed: { + var location = qmlProfilerModelProxy.getEventLocation(modelIndex, pressedItem); + if (location.hasOwnProperty("file")) // not empty + root.gotoSourceLocation(location.file, location.line, location.column); + } - // border between labels and timeline - Rectangle { - anchors.left: labels.right - anchors.top: labels.top - anchors.bottom: labelsTail.bottom - width: 1 - color: "#858585" + // hack to pass mouse events to the other mousearea if enabled + startDragArea: selectionRange.ready ? selectionRange.getLeft() : -flick.contentX + endDragArea: selectionRange.ready ? selectionRange.getRight() : -flick.contentX-1 + } + MouseArea { + id: selectionRangeControl + enabled: false + width: flick.width + height: flick.height + x: flick.contentX + y: flick.contentY + hoverEnabled: enabled + z: 2 + + onReleased: { + selectionRange.releasedOnCreation(); + } + onPressed: { + selectionRange.pressedOnCreation(); + } + onCanceled: { + selectionRange.releasedOnCreation(); + } + onPositionChanged: { + selectionRange.movedOnCreation(); + } } } ScrollView { - contentItem: vertflick - anchors.fill: parent + id: scroller + contentItem: flick + anchors.left: labelsborder.right + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.right: parent.right } SelectionRangeDetails { diff --git a/src/plugins/qmlprofiler/qml/SelectionRange.qml b/src/plugins/qmlprofiler/qml/SelectionRange.qml index f565571294e..47a1bd94b4e 100644 --- a/src/plugins/qmlprofiler/qml/SelectionRange.qml +++ b/src/plugins/qmlprofiler/qml/SelectionRange.qml @@ -107,8 +107,7 @@ RangeMover { // creation control function releasedOnCreation() { if (selectionRange.creationState === 2) { - flick.interactive = true; - vertflick.stayInteractive = true; + flick.stayInteractive = true; selectionRange.creationState = 3; selectionRangeControl.enabled = false; } @@ -116,8 +115,7 @@ RangeMover { function pressedOnCreation() { if (selectionRange.creationState === 1) { - flick.interactive = false; - vertflick.stayInteractive = false; + flick.stayInteractive = false; selectionRange.setPos(selectionRangeControl.mouseX + flick.contentX); selectionRange.creationState = 2; } diff --git a/src/plugins/qmlprofiler/qml/TimeMarks.qml b/src/plugins/qmlprofiler/qml/TimeMarks.qml index f9ac8e3590e..94e8fd058b0 100644 --- a/src/plugins/qmlprofiler/qml/TimeMarks.qml +++ b/src/plugins/qmlprofiler/qml/TimeMarks.qml @@ -128,7 +128,7 @@ Canvas { // bottom if (height > labels.height - y) { context.fillStyle = "#f5f5f5"; - context.fillRect(0, labels.height - y, width, Math.min(height - labels.height + y, labelsTail.height)); + context.fillRect(0, labels.height - y, width, height - labels.height + y); } } } -- GitLab