268 lines
10 KiB
QML
268 lines
10 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
|
|
ApplicationWindow {
|
|
id: root
|
|
width: 1000
|
|
height: 700
|
|
visible: true
|
|
title: qsTr("orkmode")
|
|
|
|
// Apply theme font globally
|
|
font.family: theme.fontFamily || Qt.application.font.family
|
|
font.pointSize: theme.fontSize > 0 ? theme.fontSize : Qt.application.font.pointSize
|
|
|
|
// Apply theme palette to Qt Quick Controls.
|
|
// theme.* colors return system palette when mode="system", override colors otherwise.
|
|
palette.active.window: theme.windowColor
|
|
palette.active.windowText: theme.windowTextColor
|
|
palette.active.base: theme.baseColor
|
|
palette.active.text: theme.textColor
|
|
palette.active.button: theme.buttonColor
|
|
palette.active.buttonText: theme.buttonTextColor
|
|
palette.active.highlight: theme.highlightColor
|
|
palette.active.highlightedText: theme.highlightedTextColor
|
|
palette.active.mid: theme.midColor
|
|
palette.active.dark: theme.darkColor
|
|
palette.active.light: theme.lightColor
|
|
palette.active.shadow: theme.shadowColor
|
|
palette.active.link: theme.linkColor
|
|
palette.active.toolTipBase: theme.tooltipBaseColor
|
|
palette.active.toolTipText: theme.tooltipTextColor
|
|
palette.active.placeholderText: theme.placeholderTextColor
|
|
palette.active.alternateBase: theme.alternateBaseColor
|
|
palette.inactive.window: theme.windowColor
|
|
palette.inactive.windowText: theme.windowTextColor
|
|
palette.inactive.base: theme.baseColor
|
|
palette.inactive.text: theme.textColor
|
|
palette.inactive.button: theme.buttonColor
|
|
palette.inactive.buttonText: theme.buttonTextColor
|
|
palette.inactive.highlight: theme.highlightColor
|
|
palette.inactive.highlightedText: theme.highlightedTextColor
|
|
palette.inactive.mid: theme.midColor
|
|
palette.inactive.dark: theme.darkColor
|
|
palette.inactive.light: theme.lightColor
|
|
palette.inactive.shadow: theme.shadowColor
|
|
palette.inactive.link: theme.linkColor
|
|
palette.inactive.toolTipBase: theme.tooltipBaseColor
|
|
palette.inactive.toolTipText: theme.tooltipTextColor
|
|
palette.inactive.placeholderText: theme.placeholderTextColor
|
|
palette.inactive.alternateBase: theme.alternateBaseColor
|
|
palette.disabled.window: theme.windowColor
|
|
palette.disabled.windowText: theme.midColor
|
|
palette.disabled.base: theme.baseColor
|
|
palette.disabled.text: theme.midColor
|
|
palette.disabled.button: theme.buttonColor
|
|
palette.disabled.buttonText: theme.midColor
|
|
palette.disabled.highlight: theme.highlightColor
|
|
palette.disabled.highlightedText: theme.highlightedTextColor
|
|
palette.disabled.mid: theme.midColor
|
|
palette.disabled.dark: theme.darkColor
|
|
palette.disabled.light: theme.lightColor
|
|
palette.disabled.shadow: theme.shadowColor
|
|
|
|
color: theme.windowColor
|
|
|
|
// Currently selected document name (namespace directory).
|
|
property string currentDoc: ""
|
|
|
|
function refreshDocs() {
|
|
docList.model = orkClient.docs()
|
|
if (docList.model.length > 0 && root.currentDoc === "")
|
|
root.selectDoc(docList.model[0].name)
|
|
}
|
|
|
|
function selectDoc(name) {
|
|
root.currentDoc = name
|
|
docModel.document = name
|
|
}
|
|
|
|
Component.onCompleted: refreshDocs()
|
|
|
|
Connections {
|
|
target: orkClient
|
|
function onConnectedChanged() { root.refreshDocs() }
|
|
// When the org path changes via Settings, the server has rescanned a
|
|
// new directory: drop the current selection and reload the doc list.
|
|
function onOrgPathChanged() {
|
|
root.currentDoc = ""
|
|
docModel.document = ""
|
|
docModel.reload()
|
|
root.refreshDocs()
|
|
}
|
|
}
|
|
|
|
// Settings dialog
|
|
SettingsDialog {
|
|
id: settingsDialog
|
|
}
|
|
|
|
// Reference font size for scalable UI
|
|
readonly property int baseFontSize: theme.fontSize > 0 ? theme.fontSize : 12
|
|
|
|
header: ToolBar {
|
|
background: Rectangle { color: theme.buttonColor }
|
|
RowLayout {
|
|
anchors.fill: parent
|
|
anchors.leftMargin: root.baseFontSize
|
|
anchors.rightMargin: root.baseFontSize
|
|
Label {
|
|
text: "orkmode"
|
|
color: theme.buttonTextColor
|
|
font.pointSize: root.baseFontSize + 2
|
|
font.bold: true
|
|
}
|
|
Item { Layout.fillWidth: true }
|
|
Label {
|
|
text: orkClient.connected
|
|
? "● " + orkClient.address
|
|
: "○ disconnected"
|
|
color: orkClient.connected ? theme.doneColor : theme.deadlineColor
|
|
font.pointSize: root.baseFontSize - 1
|
|
}
|
|
ToolButton {
|
|
text: "⟳"
|
|
onClicked: { docModel.reload(); root.refreshDocs() }
|
|
ToolTip.text: qsTr("Reload")
|
|
ToolTip.visible: hovered
|
|
}
|
|
ToolButton {
|
|
text: "⚙"
|
|
onClicked: settingsDialog.open()
|
|
ToolTip.text: qsTr("Settings")
|
|
ToolTip.visible: hovered
|
|
}
|
|
}
|
|
}
|
|
|
|
RowLayout {
|
|
anchors.fill: parent
|
|
spacing: 0
|
|
|
|
// Document sidebar.
|
|
Rectangle {
|
|
Layout.preferredWidth: root.baseFontSize * 16
|
|
Layout.fillHeight: true
|
|
color: theme.baseColor
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
spacing: 0
|
|
|
|
Label {
|
|
text: qsTr("Documents")
|
|
color: theme.placeholderTextColor
|
|
font.pointSize: root.baseFontSize - 1
|
|
font.bold: true
|
|
Layout.margins: root.baseFontSize * 0.8
|
|
}
|
|
|
|
ListView {
|
|
id: docList
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
clip: true
|
|
spacing: root.baseFontSize * 0.25
|
|
model: []
|
|
delegate: ItemDelegate {
|
|
id: docDelegate
|
|
required property var modelData
|
|
width: docList.width
|
|
highlighted: root.currentDoc === modelData.name
|
|
onClicked: root.selectDoc(modelData.name)
|
|
leftPadding: root.baseFontSize * 0.8
|
|
rightPadding: root.baseFontSize * 0.8
|
|
topPadding: root.baseFontSize * 0.5
|
|
bottomPadding: root.baseFontSize * 0.5
|
|
background: Rectangle {
|
|
color: (docDrop.containsDrag) ? theme.highlightColor
|
|
: (docDelegate.highlighted ? theme.highlightColor : "transparent")
|
|
opacity: docDrop.containsDrag ? 0.5
|
|
: (docDelegate.highlighted ? 0.3 : 1.0)
|
|
// While a section is dragged over a non-current doc,
|
|
// show a border that fills as the spring timer runs.
|
|
border.color: theme.linkColor
|
|
border.width: docDrop.containsDrag
|
|
&& modelData.name !== root.currentDoc ? 1 : 0
|
|
}
|
|
|
|
// Spring-loaded cross-file drop target: hovering a
|
|
// dragged section over another document for a moment
|
|
// switches the view to it; the drop then lands in that
|
|
// file via the outline's normal in-file resolution.
|
|
DropArea {
|
|
id: docDrop
|
|
anchors.fill: parent
|
|
keys: ["ork-section"]
|
|
onEntered: {
|
|
if (docDelegate.modelData.name !== root.currentDoc)
|
|
springTimer.restart()
|
|
}
|
|
onExited: springTimer.stop()
|
|
Timer {
|
|
id: springTimer
|
|
interval: 450
|
|
onTriggered: {
|
|
if (docDrop.containsDrag)
|
|
root.selectDoc(docDelegate.modelData.name)
|
|
}
|
|
}
|
|
}
|
|
contentItem: ColumnLayout {
|
|
spacing: root.baseFontSize * 0.3
|
|
Label {
|
|
text: modelData.title
|
|
color: theme.textColor
|
|
font.pointSize: root.baseFontSize
|
|
elide: Text.ElideRight
|
|
Layout.fillWidth: true
|
|
}
|
|
Label {
|
|
text: modelData.name
|
|
color: theme.placeholderTextColor
|
|
font.pointSize: root.baseFontSize - 2
|
|
elide: Text.ElideRight
|
|
Layout.fillWidth: true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Rectangle { Layout.preferredWidth: 1; Layout.fillHeight: true; color: theme.darkColor }
|
|
|
|
// Outline view.
|
|
Item {
|
|
Layout.fillWidth: true
|
|
Layout.fillHeight: true
|
|
|
|
OutlineView {
|
|
anchors.fill: parent
|
|
anchors.margins: root.baseFontSize * 0.6
|
|
model: docModel
|
|
// Hidden until a document is selected so its own
|
|
// "No sections" empty state does not overlap the
|
|
// "Select a document" placeholder below.
|
|
visible: root.currentDoc !== ""
|
|
}
|
|
|
|
Label {
|
|
anchors.centerIn: parent
|
|
width: Math.min(parent.width - root.baseFontSize * 4,
|
|
root.baseFontSize * 30)
|
|
visible: root.currentDoc === ""
|
|
text: orkClient.connected
|
|
? qsTr("Select a document")
|
|
: qsTr("Not connected: %1").arg(orkClient.error)
|
|
color: theme.placeholderTextColor
|
|
font.pointSize: root.baseFontSize + 1
|
|
horizontalAlignment: Text.AlignHCenter
|
|
wrapMode: Text.WordWrap
|
|
lineHeight: 1.3
|
|
}
|
|
}
|
|
}
|
|
}
|