forked from qt-creator/qt-creator
Unify flame graph and timeline details windows
They are mostly the same. Change-Id: I41be570989ecc58cf2ae33f692c89946b55a0e1d Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
@@ -57,7 +57,7 @@ Item {
|
|||||||
anchors.right: flamegraphItem.right
|
anchors.right: flamegraphItem.right
|
||||||
anchors.bottom: flamegraphItem.bottom
|
anchors.bottom: flamegraphItem.bottom
|
||||||
|
|
||||||
FlameGraphText {
|
TimelineText {
|
||||||
id: text
|
id: text
|
||||||
visible: textVisible
|
visible: textVisible
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|||||||
@@ -1,234 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
** Contact: https://www.qt.io/licensing/
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator.
|
|
||||||
**
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and The Qt Company. For licensing terms
|
|
||||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
||||||
** information use the contact form at https://www.qt.io/contact-us.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3 as published by the Free Software
|
|
||||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
||||||
** included in the packaging of this file. Please review the following
|
|
||||||
** information to ensure the GNU General Public License requirements will
|
|
||||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
import QtQuick 2.1
|
|
||||||
import QtQuick.Controls 1.4
|
|
||||||
import QtQuick.Controls.Styles 1.4
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: rangeDetails
|
|
||||||
|
|
||||||
property color titleBarColor: "#55a3b8"
|
|
||||||
property color titleBarTextColor: "white"
|
|
||||||
property color contentColor: "white"
|
|
||||||
property color contentTextColor: "black"
|
|
||||||
property color borderColor: "#a0a0a0"
|
|
||||||
property color noteTextColor: "orange"
|
|
||||||
property color buttonSelectedColor: titleBarColor
|
|
||||||
property color buttonHoveredColor: titleBarColor
|
|
||||||
|
|
||||||
property real titleBarHeight: 20
|
|
||||||
property real borderWidth: 1
|
|
||||||
property real outerMargin: 10
|
|
||||||
property real innerMargin: 5
|
|
||||||
property real minimumInnerWidth: 150
|
|
||||||
property real initialWidth: 300
|
|
||||||
|
|
||||||
property real minimumX
|
|
||||||
property real maximumX
|
|
||||||
property real minimumY
|
|
||||||
property real maximumY
|
|
||||||
|
|
||||||
property string dialogTitle
|
|
||||||
property var model
|
|
||||||
property string note
|
|
||||||
|
|
||||||
signal clearSelection
|
|
||||||
|
|
||||||
visible: dialogTitle.length > 0 || model.length > 0
|
|
||||||
|
|
||||||
width: dragHandle.x + dragHandle.width
|
|
||||||
height: contentArea.height + titleBar.height
|
|
||||||
|
|
||||||
onMinimumXChanged: x = Math.max(x, minimumX)
|
|
||||||
onMaximumXChanged: x = Math.min(x, Math.max(minimumX, maximumX - width))
|
|
||||||
onMinimumYChanged: y = Math.max(y, minimumY)
|
|
||||||
onMaximumYChanged: y = Math.min(y, Math.max(minimumY, maximumY - height))
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
drag.target: parent
|
|
||||||
drag.minimumX: parent.minimumX
|
|
||||||
drag.maximumX: parent.maximumX - rangeDetails.width
|
|
||||||
drag.minimumY: parent.minimumY
|
|
||||||
drag.maximumY: parent.maximumY - rangeDetails.height
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: titleBar
|
|
||||||
width: parent.width
|
|
||||||
height: titleBarHeight
|
|
||||||
color: titleBarColor
|
|
||||||
border.width: borderWidth
|
|
||||||
border.color: borderColor
|
|
||||||
|
|
||||||
FlameGraphText {
|
|
||||||
id: typeTitle
|
|
||||||
text: rangeDetails.dialogTitle
|
|
||||||
font.bold: true
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: closeIcon.left
|
|
||||||
anchors.leftMargin: outerMargin
|
|
||||||
anchors.rightMargin: innerMargin
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
color: titleBarTextColor
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
ToolButton {
|
|
||||||
id: closeIcon
|
|
||||||
|
|
||||||
implicitWidth: 30
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.top: parent.top
|
|
||||||
anchors.bottom: parent.bottom
|
|
||||||
onClicked: rangeDetails.clearSelection()
|
|
||||||
|
|
||||||
Image {
|
|
||||||
id: image
|
|
||||||
source: "image://icons/close_window" + (parent.enabled ? "" : "/disabled")
|
|
||||||
width: 16
|
|
||||||
height: 16
|
|
||||||
anchors.centerIn: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
style: ButtonStyle {
|
|
||||||
background: Rectangle {
|
|
||||||
color: (control.checked || control.pressed)
|
|
||||||
? buttonSelectedColor
|
|
||||||
: control.hovered
|
|
||||||
? buttonHoveredColor
|
|
||||||
: "#00000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
id: contentArea
|
|
||||||
color: contentColor
|
|
||||||
|
|
||||||
anchors.top: titleBar.bottom
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.bottom: dragHandle.bottom
|
|
||||||
|
|
||||||
border.width: borderWidth
|
|
||||||
border.color: borderColor
|
|
||||||
}
|
|
||||||
|
|
||||||
Grid {
|
|
||||||
id: col
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.top: titleBar.bottom
|
|
||||||
anchors.topMargin: innerMargin
|
|
||||||
anchors.leftMargin: outerMargin
|
|
||||||
anchors.rightMargin: outerMargin
|
|
||||||
|
|
||||||
spacing: innerMargin
|
|
||||||
columns: 2
|
|
||||||
property int minimumWidth: {
|
|
||||||
// max(width of longest label * 2, minimumInnerWidth)
|
|
||||||
var result = minimumInnerWidth;
|
|
||||||
for (var i = 0; i < children.length; ++i) {
|
|
||||||
if (children[i].isLabel)
|
|
||||||
result = Math.max(children[i].implicitWidth * 2 + innerMargin, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
return result + 2 * outerMargin;
|
|
||||||
}
|
|
||||||
|
|
||||||
property int labelWidth: (minimumWidth - innerMargin) / 2 - outerMargin
|
|
||||||
property int valueWidth: dragHandle.x - labelWidth - innerMargin - outerMargin
|
|
||||||
|
|
||||||
onMinimumWidthChanged: {
|
|
||||||
if (dragHandle.x < minimumWidth - outerMargin)
|
|
||||||
dragHandle.x = minimumWidth - outerMargin;
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: rangeDetails.model
|
|
||||||
FlameGraphText {
|
|
||||||
property bool isLabel: index % 2 === 0
|
|
||||||
font.bold: isLabel
|
|
||||||
elide: Text.ElideRight
|
|
||||||
width: isLabel ? col.labelWidth : col.valueWidth
|
|
||||||
text: isLabel ? (modelData + ":") : modelData
|
|
||||||
color: contentTextColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TextEdit {
|
|
||||||
id: noteEdit
|
|
||||||
|
|
||||||
anchors.left: parent.left
|
|
||||||
anchors.right: parent.right
|
|
||||||
anchors.leftMargin: outerMargin
|
|
||||||
anchors.rightMargin: outerMargin
|
|
||||||
anchors.topMargin: visible ? innerMargin : 0
|
|
||||||
anchors.top: col.bottom
|
|
||||||
height: visible ? implicitHeight : 0
|
|
||||||
|
|
||||||
readOnly: true
|
|
||||||
visible: text.length > 0
|
|
||||||
text: note
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
color: noteTextColor
|
|
||||||
font.italic: true
|
|
||||||
font.pixelSize: typeTitle.font.pixelSize
|
|
||||||
font.family: typeTitle.font.family
|
|
||||||
renderType: typeTitle.renderType
|
|
||||||
selectByMouse: true
|
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
|
||||||
id: dragHandle
|
|
||||||
width: outerMargin
|
|
||||||
height: outerMargin
|
|
||||||
x: initialWidth
|
|
||||||
anchors.top: noteEdit.bottom
|
|
||||||
clip: true
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
drag.target: parent
|
|
||||||
drag.minimumX: col.minimumWidth - outerMargin
|
|
||||||
drag.axis: Drag.XAxis
|
|
||||||
cursorShape: Qt.SizeHorCursor
|
|
||||||
}
|
|
||||||
Rectangle {
|
|
||||||
color: titleBarColor
|
|
||||||
rotation: 45
|
|
||||||
width: parent.width * Math.SQRT2
|
|
||||||
height: parent.height * Math.SQRT2
|
|
||||||
x: parent.width - width / 2
|
|
||||||
y: parent.height - height / 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
**
|
|
||||||
** Copyright (C) 2016 The Qt Company Ltd.
|
|
||||||
** Contact: https://www.qt.io/licensing/
|
|
||||||
**
|
|
||||||
** This file is part of Qt Creator.
|
|
||||||
**
|
|
||||||
** Commercial License Usage
|
|
||||||
** Licensees holding valid commercial Qt licenses may use this file in
|
|
||||||
** accordance with the commercial license agreement provided with the
|
|
||||||
** Software or, alternatively, in accordance with the terms contained in
|
|
||||||
** a written agreement between you and The Qt Company. For licensing terms
|
|
||||||
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
||||||
** information use the contact form at https://www.qt.io/contact-us.
|
|
||||||
**
|
|
||||||
** GNU General Public License Usage
|
|
||||||
** Alternatively, this file may be used under the terms of the GNU
|
|
||||||
** General Public License version 3 as published by the Free Software
|
|
||||||
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
||||||
** included in the packaging of this file. Please review the following
|
|
||||||
** information to ensure the GNU General Public License requirements will
|
|
||||||
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
||||||
**
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
import QtQuick 2.0
|
|
||||||
|
|
||||||
Text {
|
|
||||||
font.pixelSize: 12
|
|
||||||
font.family: "sans-serif"
|
|
||||||
textFormat: Text.PlainText
|
|
||||||
renderType: Text.NativeRendering
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -265,21 +265,15 @@ ScrollView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FlameGraphDetails {
|
RangeDetails {
|
||||||
id: tooltip
|
id: tooltip
|
||||||
|
|
||||||
minimumX: 0
|
minimumX: 0
|
||||||
maximumX: flickable.width
|
maximumX: flickable.width
|
||||||
minimumY: flickable.contentY
|
minimumY: flickable.contentY
|
||||||
maximumY: flickable.contentY + flickable.height
|
maximumY: flickable.contentY + flickable.height
|
||||||
|
noteReadonly: true
|
||||||
|
|
||||||
titleBarColor: Theme.color(Theme.Timeline_PanelHeaderColor)
|
|
||||||
titleBarTextColor: Theme.color(Theme.PanelTextColorLight)
|
|
||||||
contentColor: Theme.color(Theme.Timeline_PanelBackgroundColor)
|
|
||||||
contentTextColor: Theme.color(Theme.Timeline_TextColor)
|
|
||||||
noteTextColor: Theme.color(Theme.Timeline_HighlightColor)
|
|
||||||
buttonHoveredColor: Theme.color(Theme.FancyToolButtonHoverColor)
|
|
||||||
buttonSelectedColor: Theme.color(Theme.FancyToolButtonSelectedColor)
|
|
||||||
borderWidth: 0
|
borderWidth: 0
|
||||||
|
|
||||||
property var hoveredNode: null;
|
property var hoveredNode: null;
|
||||||
@@ -310,7 +304,7 @@ ScrollView {
|
|||||||
}
|
}
|
||||||
|
|
||||||
model: currentNode ? currentNode.details() : []
|
model: currentNode ? currentNode.details() : []
|
||||||
note: currentNode ? currentNode.note() : ""
|
noteText: currentNode ? currentNode.note() : ""
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: root.model
|
target: root.model
|
||||||
|
|||||||
@@ -224,11 +224,12 @@ Rectangle {
|
|||||||
if (selectedModel !== -1 && selectedModel !== newModel)
|
if (selectedModel !== -1 && selectedModel !== newModel)
|
||||||
select(selectedModel, -1);
|
select(selectedModel, -1);
|
||||||
|
|
||||||
|
rangeDetails.saveNote();
|
||||||
selectedItem = newItem
|
selectedItem = newItem
|
||||||
selectedModel = newModel
|
selectedModel = newModel
|
||||||
if (selectedItem !== -1) {
|
if (selectedItem !== -1) {
|
||||||
// display details
|
// display details
|
||||||
rangeDetails.showInfo(selectedModel, selectedItem);
|
rangeDetails.showInfo();
|
||||||
|
|
||||||
// update in other views
|
// update in other views
|
||||||
var model = timelineModelAggregator.models[selectedModel];
|
var model = timelineModelAggregator.models[selectedModel];
|
||||||
@@ -362,20 +363,73 @@ Rectangle {
|
|||||||
x: 200
|
x: 200
|
||||||
y: 25
|
y: 25
|
||||||
|
|
||||||
|
noteReadonly: false
|
||||||
clip: true
|
clip: true
|
||||||
locked: content.selectionLocked
|
locked: content.selectionLocked
|
||||||
models: timelineModelAggregator.models
|
|
||||||
notes: timelineModelAggregator.notes
|
|
||||||
hasContents: false
|
|
||||||
onRecenterOnItem: {
|
onRecenterOnItem: {
|
||||||
content.select(selectedModel, selectedItem)
|
content.select(selectedModel, selectedItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
onToggleSelectionLocked: {
|
onToggleSelectionLocked: {
|
||||||
content.selectionLocked = !content.selectionLocked;
|
content.selectionLocked = !content.selectionLocked;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClearSelection: {
|
onClearSelection: {
|
||||||
content.propagateSelection(-1, -1);
|
content.propagateSelection(-1, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUpdateNote: {
|
||||||
|
if (timelineModelAggregator.notes && selectedModel != -1 && selectedItem != -1) {
|
||||||
|
timelineModelAggregator.notes.setText(
|
||||||
|
timelineModelAggregator.models[selectedModel].modelId,
|
||||||
|
selectedItem, text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide() {
|
||||||
|
model = [];
|
||||||
|
file = "";
|
||||||
|
line = -1;
|
||||||
|
column = 0;
|
||||||
|
noteText = "";
|
||||||
|
dialogTitle = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveNote() {
|
||||||
|
noteFocus = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function showInfo() {
|
||||||
|
var timelineModel = timelineModelAggregator.models[selectedModel];
|
||||||
|
var eventData = timelineModel.details(selectedItem)
|
||||||
|
var content = [];
|
||||||
|
for (var k in eventData) {
|
||||||
|
if (k === "displayName") {
|
||||||
|
dialogTitle = eventData[k];
|
||||||
|
} else {
|
||||||
|
content.push(k);
|
||||||
|
content.push(eventData[k]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rangeDetails.model = content;
|
||||||
|
|
||||||
|
var location = timelineModel.location(selectedItem)
|
||||||
|
if (location.hasOwnProperty("file")) { // not empty
|
||||||
|
rangeDetails.file = location.file;
|
||||||
|
rangeDetails.line = location.line;
|
||||||
|
rangeDetails.column = location.column;
|
||||||
|
} else {
|
||||||
|
// reset to default values
|
||||||
|
rangeDetails.file = "";
|
||||||
|
rangeDetails.line = 0;
|
||||||
|
rangeDetails.column = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
var notes = timelineModelAggregator.notes;
|
||||||
|
var noteId = notes ? notes.get(timelineModel.modelId, selectedItem) : -1;
|
||||||
|
rangeDetails.noteText = (noteId !== -1) ? notes.text(noteId) : "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
|
|||||||
@@ -29,240 +29,85 @@ import TimelineTheme 1.0
|
|||||||
Item {
|
Item {
|
||||||
id: rangeDetails
|
id: rangeDetails
|
||||||
|
|
||||||
property string duration
|
property real titleBarHeight: 20
|
||||||
property string label
|
property real borderWidth: 1
|
||||||
property string dialogTitle
|
property real outerMargin: 10
|
||||||
property string file
|
property real innerMargin: 5
|
||||||
property int line
|
property real minimumInnerWidth: 150
|
||||||
property int column
|
property real initialWidth: 300
|
||||||
property bool isBindingLoop
|
|
||||||
property bool hasContents
|
|
||||||
|
|
||||||
property int selectedModel: -1
|
property real minimumX: 0
|
||||||
property int selectedItem: -1
|
property real maximumX: parent.width
|
||||||
|
property real minimumY: 0
|
||||||
|
property real maximumY: parent.height
|
||||||
|
|
||||||
property bool locked
|
property string dialogTitle: ""
|
||||||
|
property string file: ""
|
||||||
|
property int line: -1
|
||||||
|
property int column: -1
|
||||||
|
|
||||||
property var models
|
property bool locked: false
|
||||||
property var notes
|
property var model: []
|
||||||
|
|
||||||
|
property alias noteText: noteEdit.text
|
||||||
|
property alias noteFocus: noteEdit.focus
|
||||||
|
property alias noteReadonly: noteEdit.readOnly
|
||||||
|
|
||||||
signal recenterOnItem
|
signal recenterOnItem
|
||||||
signal toggleSelectionLocked
|
signal toggleSelectionLocked
|
||||||
signal clearSelection
|
signal clearSelection
|
||||||
|
signal updateNote(string text)
|
||||||
|
|
||||||
width: col.width + 20
|
visible: dialogTitle.length > 0 || model.length > 0
|
||||||
height: hasContents ? contentArea.height + titleBar.height : 0
|
|
||||||
|
|
||||||
function hide() {
|
width: dragHandle.x + dragHandle.width
|
||||||
noteEdit.focus = false;
|
height: contentArea.height + titleBar.height
|
||||||
hasContents = false;
|
|
||||||
selectedModel = selectedItem = -1;
|
|
||||||
noteEdit.text = "";
|
|
||||||
duration = "";
|
|
||||||
label = "";
|
|
||||||
file = "";
|
|
||||||
line = -1;
|
|
||||||
column = 0;
|
|
||||||
isBindingLoop = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Connections {
|
onMinimumXChanged: x = Math.max(x, minimumX)
|
||||||
target: rangeDetails.parent
|
onMaximumXChanged: x = Math.min(x, Math.max(minimumX, maximumX - width))
|
||||||
// keep inside view
|
onMinimumYChanged: y = Math.max(y, minimumY)
|
||||||
onWidthChanged: fitInView();
|
onMaximumYChanged: y = Math.min(y, Math.max(minimumY, maximumY - height))
|
||||||
onHeightChanged: fitInView();
|
|
||||||
}
|
|
||||||
|
|
||||||
QtObject {
|
MouseArea {
|
||||||
id: eventInfo
|
anchors.fill: parent
|
||||||
property bool ready: false
|
drag.target: parent
|
||||||
property var content: []
|
drag.minimumX: parent.minimumX
|
||||||
}
|
drag.maximumX: parent.maximumX - rangeDetails.width
|
||||||
|
drag.minimumY: parent.minimumY
|
||||||
function showInfo(model, item) {
|
drag.maximumY: parent.maximumY - rangeDetails.height
|
||||||
eventInfo.ready = false;
|
onClicked: rangeDetails.recenterOnItem()
|
||||||
// make sure we don't accidentally save the old text for the new event
|
|
||||||
noteEdit.focus = false;
|
|
||||||
|
|
||||||
selectedModel = model;
|
|
||||||
selectedItem = item;
|
|
||||||
var timelineModel = models[selectedModel];
|
|
||||||
var eventData = timelineModel.details(selectedItem)
|
|
||||||
eventInfo.content = [];
|
|
||||||
for (var k in eventData) {
|
|
||||||
if (k === "displayName") {
|
|
||||||
dialogTitle = eventData[k];
|
|
||||||
} else {
|
|
||||||
eventInfo.content.push(k);
|
|
||||||
eventInfo.content.push(eventData[k]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
eventInfo.ready = true;
|
|
||||||
hasContents = eventInfo.content.length > 0;
|
|
||||||
|
|
||||||
var location = timelineModel.location(selectedItem)
|
|
||||||
if (location.hasOwnProperty("file")) { // not empty
|
|
||||||
file = location.file;
|
|
||||||
line = location.line;
|
|
||||||
column = location.column;
|
|
||||||
} else {
|
|
||||||
// reset to default values
|
|
||||||
file = "";
|
|
||||||
line = 0;
|
|
||||||
column = -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
noteEdit.focus = false;
|
|
||||||
var noteId = notes ? notes.get(timelineModel.modelId, selectedItem) : -1;
|
|
||||||
noteEdit.text = (noteId !== -1) ? notes.text(noteId) : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
function fitInView() {
|
|
||||||
// don't reposition if it does not fit
|
|
||||||
if (parent.width < width || parent.height < height)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (x + width > parent.width)
|
|
||||||
x = parent.width - width;
|
|
||||||
if (x < 0)
|
|
||||||
x = 0;
|
|
||||||
if (y + height > parent.height)
|
|
||||||
y = parent.height - height;
|
|
||||||
if (y < 0)
|
|
||||||
y = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: titleBar
|
id: titleBar
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 20
|
height: titleBarHeight
|
||||||
color: Theme.color(Theme.Timeline_PanelHeaderColor)
|
color: Theme.color(Theme.Timeline_PanelHeaderColor)
|
||||||
}
|
border.width: borderWidth
|
||||||
Item {
|
border.color: Theme.color(Theme.PanelTextColorMid)
|
||||||
width: parent.width+1
|
|
||||||
height: 11
|
|
||||||
y: 10
|
|
||||||
clip: true
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width-1
|
|
||||||
height: 15
|
|
||||||
y: -5
|
|
||||||
color: Theme.color(Theme.Timeline_PanelHeaderColor)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//title
|
|
||||||
TimelineText {
|
TimelineText {
|
||||||
id: typeTitle
|
id: typeTitle
|
||||||
text: " "+rangeDetails.dialogTitle
|
text: rangeDetails.dialogTitle
|
||||||
font.bold: true
|
font.bold: true
|
||||||
height: 20
|
|
||||||
verticalAlignment: Text.AlignVCenter
|
verticalAlignment: Text.AlignVCenter
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: editIcon.left
|
anchors.right: closeIcon.left
|
||||||
elide: Text.ElideRight
|
anchors.leftMargin: outerMargin
|
||||||
|
anchors.rightMargin: innerMargin
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
color: Theme.color(Theme.PanelTextColorLight)
|
color: Theme.color(Theme.PanelTextColorLight)
|
||||||
}
|
elide: Text.ElideRight
|
||||||
|
|
||||||
// Details area
|
|
||||||
Rectangle {
|
|
||||||
id: contentArea
|
|
||||||
color: Theme.color(Theme.Timeline_PanelBackgroundColor)
|
|
||||||
width: parent.width
|
|
||||||
height: 10 + col.height + (noteEdit.visible ? (noteEdit.height + 5) : 0)
|
|
||||||
y: 20
|
|
||||||
|
|
||||||
//details
|
|
||||||
Grid {
|
|
||||||
property int outerMargin: 10
|
|
||||||
property int minimumWidth: 150
|
|
||||||
property int labelWidth: (minimumWidth - spacing) / 2 - outerMargin
|
|
||||||
property int valueWidth: dragHandle.x - labelWidth - spacing - outerMargin
|
|
||||||
|
|
||||||
id: col
|
|
||||||
x: outerMargin
|
|
||||||
y: 5
|
|
||||||
spacing: 5
|
|
||||||
columns: 2
|
|
||||||
|
|
||||||
onChildrenChanged: {
|
|
||||||
// max(width of longest label * 2, 150)
|
|
||||||
var result = 150;
|
|
||||||
for (var i = 0; i < children.length; ++i) {
|
|
||||||
if (children[i].isLabel)
|
|
||||||
result = Math.max(children[i].implicitWidth * 2 + spacing, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
minimumWidth = result + 2 * outerMargin;
|
|
||||||
if (dragHandle.x < minimumWidth - outerMargin)
|
|
||||||
dragHandle.x = minimumWidth - outerMargin;
|
|
||||||
}
|
|
||||||
|
|
||||||
Repeater {
|
|
||||||
model: eventInfo.ready ? eventInfo.content : 0
|
|
||||||
Detail {
|
|
||||||
labelWidth: col.labelWidth
|
|
||||||
valueWidth: col.valueWidth
|
|
||||||
isLabel: index % 2 === 0
|
|
||||||
text: isLabel ? (modelData + ":") : modelData
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
TextEdit {
|
|
||||||
id: noteEdit
|
|
||||||
x: 10
|
|
||||||
anchors.topMargin: 5
|
|
||||||
anchors.bottomMargin: 5
|
|
||||||
anchors.top: col.bottom
|
|
||||||
|
|
||||||
visible: notes && (text.length > 0 || focus)
|
|
||||||
width: col.width
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
color: Theme.color(Theme.Timeline_HighlightColor)
|
|
||||||
font.italic: true
|
|
||||||
font.pixelSize: typeTitle.font.pixelSize
|
|
||||||
font.family: typeTitle.font.family
|
|
||||||
renderType: typeTitle.renderType
|
|
||||||
selectByMouse: true
|
|
||||||
onTextChanged: saveTimer.restart()
|
|
||||||
onFocusChanged: {
|
|
||||||
if (!focus && selectedModel != -1 && selectedItem != -1) {
|
|
||||||
saveTimer.stop();
|
|
||||||
if (notes)
|
|
||||||
notes.setText(models[selectedModel].modelId, selectedItem, text);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Timer {
|
|
||||||
id: saveTimer
|
|
||||||
onTriggered: {
|
|
||||||
if (notes && selectedModel != -1 && selectedItem != -1)
|
|
||||||
notes.setText(models[selectedModel].modelId, selectedItem, noteEdit.text);
|
|
||||||
}
|
|
||||||
interval: 1000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
drag.target: parent
|
|
||||||
drag.minimumX: 0
|
|
||||||
drag.maximumX: rangeDetails.parent.width - rangeDetails.width
|
|
||||||
drag.minimumY: 0
|
|
||||||
drag.maximumY: rangeDetails.parent.height - rangeDetails.height
|
|
||||||
onClicked: rangeDetails.recenterOnItem()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ImageToolButton {
|
ImageToolButton {
|
||||||
id: editIcon
|
id: editIcon
|
||||||
imageSource: "image://icons/edit"
|
imageSource: "image://icons/edit"
|
||||||
anchors.top: closeIcon.top
|
anchors.top: parent.top
|
||||||
anchors.right: lockIcon.left
|
anchors.right: lockIcon.left
|
||||||
implicitHeight: typeTitle.height
|
implicitHeight: typeTitle.height
|
||||||
visible: notes
|
visible: !rangeDetails.noteReadonly
|
||||||
onClicked: noteEdit.focus = true
|
onClicked: noteEdit.focus = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -283,18 +128,114 @@ Item {
|
|||||||
imageSource: "image://icons/close_window"
|
imageSource: "image://icons/close_window"
|
||||||
onClicked: rangeDetails.clearSelection()
|
onClicked: rangeDetails.clearSelection()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: contentArea
|
||||||
|
color: Theme.color(Theme.Timeline_PanelBackgroundColor)
|
||||||
|
|
||||||
|
anchors.top: titleBar.bottom
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.bottom: dragHandle.bottom
|
||||||
|
|
||||||
|
border.width: borderWidth
|
||||||
|
border.color: Theme.color(Theme.PanelTextColorMid)
|
||||||
|
}
|
||||||
|
|
||||||
|
Grid {
|
||||||
|
id: col
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.top: titleBar.bottom
|
||||||
|
anchors.topMargin: innerMargin
|
||||||
|
anchors.leftMargin: outerMargin
|
||||||
|
anchors.rightMargin: outerMargin
|
||||||
|
|
||||||
|
spacing: innerMargin
|
||||||
|
columns: 2
|
||||||
|
property int minimumWidth: {
|
||||||
|
// max(width of longest label * 2, minimumInnerWidth)
|
||||||
|
var result = minimumInnerWidth;
|
||||||
|
for (var i = 0; i < children.length; ++i) {
|
||||||
|
if (children[i].isLabel)
|
||||||
|
result = Math.max(children[i].implicitWidth * 2 + innerMargin, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result + 2 * outerMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
property int labelWidth: (minimumWidth - innerMargin) / 2 - outerMargin
|
||||||
|
property int valueWidth: dragHandle.x - labelWidth - innerMargin - outerMargin
|
||||||
|
|
||||||
|
onMinimumWidthChanged: {
|
||||||
|
if (dragHandle.x < minimumWidth - outerMargin)
|
||||||
|
dragHandle.x = minimumWidth - outerMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: rangeDetails.model
|
||||||
|
Detail {
|
||||||
|
labelWidth: col.labelWidth
|
||||||
|
valueWidth: col.valueWidth
|
||||||
|
isLabel: index % 2 === 0
|
||||||
|
text: isLabel ? (modelData + ":") : modelData
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
TextEdit {
|
||||||
|
id: noteEdit
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.leftMargin: outerMargin
|
||||||
|
anchors.rightMargin: outerMargin
|
||||||
|
anchors.topMargin: visible ? innerMargin : 0
|
||||||
|
anchors.top: col.bottom
|
||||||
|
height: visible ? implicitHeight : 0
|
||||||
|
|
||||||
|
readOnly: rangeDetails.noteReadonly
|
||||||
|
visible: (text.length > 0 || focus)
|
||||||
|
wrapMode: Text.Wrap
|
||||||
|
color: Theme.color(Theme.Timeline_HighlightColor)
|
||||||
|
font.italic: true
|
||||||
|
font.pixelSize: typeTitle.font.pixelSize
|
||||||
|
font.family: typeTitle.font.family
|
||||||
|
renderType: typeTitle.renderType
|
||||||
|
selectByMouse: true
|
||||||
|
onTextChanged: saveTimer.restart()
|
||||||
|
onFocusChanged: {
|
||||||
|
if (!focus) {
|
||||||
|
saveTimer.stop();
|
||||||
|
if (!readOnly)
|
||||||
|
rangeDetails.updateNote(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Timer {
|
||||||
|
id: saveTimer
|
||||||
|
onTriggered: {
|
||||||
|
if (!rangeDetails.readOnly)
|
||||||
|
rangeDetails.updateNote(noteEdit.text);
|
||||||
|
}
|
||||||
|
interval: 1000
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: dragHandle
|
id: dragHandle
|
||||||
width: 10
|
width: outerMargin
|
||||||
height: 10
|
height: outerMargin
|
||||||
x: 300
|
x: initialWidth
|
||||||
anchors.bottom: parent.bottom
|
anchors.top: noteEdit.bottom
|
||||||
clip: true
|
clip: true
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
drag.target: parent
|
drag.target: parent
|
||||||
drag.minimumX: col.minimumWidth - col.outerMargin
|
drag.minimumX: col.minimumWidth - outerMargin
|
||||||
drag.axis: Drag.XAxis
|
drag.axis: Drag.XAxis
|
||||||
cursorShape: Qt.SizeHorCursor
|
cursorShape: Qt.SizeHorCursor
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@
|
|||||||
<file>CategoryLabel.qml</file>
|
<file>CategoryLabel.qml</file>
|
||||||
<file>Detail.qml</file>
|
<file>Detail.qml</file>
|
||||||
<file>FlameGraphDelegate.qml</file>
|
<file>FlameGraphDelegate.qml</file>
|
||||||
<file>FlameGraphDetails.qml</file>
|
|
||||||
<file>FlameGraphText.qml</file>
|
|
||||||
<file>FlameGraphView.qml</file>
|
<file>FlameGraphView.qml</file>
|
||||||
<file>ico_edit.png</file>
|
<file>ico_edit.png</file>
|
||||||
<file>ico_edit@2x.png</file>
|
<file>ico_edit@2x.png</file>
|
||||||
|
|||||||
Reference in New Issue
Block a user