324 lines
9.7 KiB
QML
324 lines
9.7 KiB
QML
import QtQuick
|
|
import QtQuick.Controls
|
|
import QtQuick.Layouts
|
|
import QtQuick.Dialogs
|
|
|
|
Dialog {
|
|
id: settingsDialog
|
|
title: qsTr("Settings")
|
|
modal: true
|
|
standardButtons: Dialog.Close
|
|
width: 450
|
|
height: 520
|
|
|
|
x: (parent.width - width) / 2
|
|
y: (parent.height - height) / 2
|
|
|
|
// Load the current org path from the server whenever the dialog opens.
|
|
onOpened: {
|
|
orgPathField.text = orkClient.orgPath()
|
|
orgPathStatus.clear()
|
|
}
|
|
|
|
// Native folder picker. Writes the chosen local path into the field; the
|
|
// user still presses Apply to send it to the server.
|
|
FolderDialog {
|
|
id: folderDialog
|
|
title: qsTr("Select Org Directory")
|
|
onAccepted: {
|
|
// selectedFolder is a file:// URL; convert to a local path.
|
|
orgPathField.text = decodeURIComponent(
|
|
selectedFolder.toString().replace(/^file:\/\//, ""))
|
|
}
|
|
}
|
|
|
|
// Send the field's path to the server via /cfg. On success, refresh the
|
|
// document list; on failure, show the server's error message.
|
|
function applyOrgPath() {
|
|
var path = orgPathField.text.trim()
|
|
if (path.length === 0) {
|
|
orgPathStatus.ok = false
|
|
orgPathStatus.text = qsTr("Path is empty.")
|
|
return
|
|
}
|
|
if (orkClient.setOrgPath(path)) {
|
|
orgPathStatus.ok = true
|
|
orgPathStatus.text = qsTr("Applied. Scanning %1").arg(path)
|
|
} else {
|
|
orgPathStatus.ok = false
|
|
orgPathStatus.text = qsTr("Failed: %1").arg(orkClient.error)
|
|
}
|
|
}
|
|
|
|
background: Rectangle {
|
|
color: theme.windowColor
|
|
border.color: theme.midColor
|
|
border.width: 1
|
|
radius: 6
|
|
}
|
|
|
|
header: Rectangle {
|
|
implicitHeight: 40
|
|
color: theme.buttonColor
|
|
radius: 6
|
|
|
|
Label {
|
|
anchors.centerIn: parent
|
|
text: settingsDialog.title
|
|
color: theme.buttonTextColor
|
|
font.bold: true
|
|
font.pointSize: theme.fontSize > 0 ? theme.fontSize + 1 : 13
|
|
}
|
|
|
|
// Square off bottom corners
|
|
Rectangle {
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.bottom: parent.bottom
|
|
height: 6
|
|
color: theme.buttonColor
|
|
}
|
|
}
|
|
|
|
contentItem: ScrollView {
|
|
id: contentScroll
|
|
clip: true
|
|
// Only scroll vertically; the inner layout matches the viewport width.
|
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
|
contentWidth: availableWidth
|
|
|
|
ColumnLayout {
|
|
// Match the scroll viewport width so Layout.fillWidth children size
|
|
// correctly and no horizontal scrolling is needed.
|
|
width: contentScroll.availableWidth
|
|
spacing: 16
|
|
|
|
// --- Org Path ---
|
|
GroupBox {
|
|
title: qsTr("Org Path")
|
|
Layout.fillWidth: true
|
|
|
|
background: Rectangle {
|
|
color: "transparent"
|
|
border.color: theme.midColor
|
|
border.width: 1
|
|
radius: 4
|
|
y: 12
|
|
}
|
|
|
|
label: Label {
|
|
x: 8
|
|
text: parent.title
|
|
color: theme.textColor
|
|
font.pointSize: theme.fontSize > 0 ? theme.fontSize * 0.9 : 11
|
|
}
|
|
|
|
ColumnLayout {
|
|
anchors.fill: parent
|
|
spacing: 8
|
|
|
|
Label {
|
|
text: qsTr("Directory the server scans for .org files. A leading ~ expands to your home directory.")
|
|
color: theme.placeholderTextColor
|
|
font.pointSize: theme.fontSize > 0 ? theme.fontSize * 0.85 : 10
|
|
wrapMode: Text.WordWrap
|
|
Layout.fillWidth: true
|
|
}
|
|
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 8
|
|
|
|
TextField {
|
|
id: orgPathField
|
|
Layout.fillWidth: true
|
|
placeholderText: qsTr("e.g. ~/org")
|
|
selectByMouse: true
|
|
onAccepted: applyOrgPath()
|
|
}
|
|
|
|
Button {
|
|
text: qsTr("Browse…")
|
|
onClicked: folderDialog.open()
|
|
}
|
|
|
|
Button {
|
|
text: qsTr("Apply")
|
|
onClicked: applyOrgPath()
|
|
}
|
|
}
|
|
|
|
Label {
|
|
id: orgPathStatus
|
|
Layout.fillWidth: true
|
|
wrapMode: Text.WordWrap
|
|
visible: text.length > 0
|
|
font.pointSize: theme.fontSize > 0 ? theme.fontSize * 0.85 : 10
|
|
// ok/err color set by applyOrgPath via property.
|
|
property bool ok: true
|
|
color: ok ? theme.doneColor : theme.deadlineColor
|
|
function clear() { text = "" }
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Color Scheme ---
|
|
GroupBox {
|
|
title: qsTr("Color Scheme")
|
|
Layout.fillWidth: true
|
|
|
|
background: Rectangle {
|
|
color: "transparent"
|
|
border.color: theme.midColor
|
|
border.width: 1
|
|
radius: 4
|
|
y: 12
|
|
}
|
|
|
|
label: Label {
|
|
x: 8
|
|
text: parent.title
|
|
color: theme.textColor
|
|
font.pointSize: theme.fontSize > 0 ? theme.fontSize * 0.9 : 11
|
|
}
|
|
|
|
RowLayout {
|
|
anchors.fill: parent
|
|
spacing: 8
|
|
|
|
ComboBox {
|
|
id: schemeCombo
|
|
Layout.fillWidth: true
|
|
model: theme.availableSchemes
|
|
currentIndex: {
|
|
let idx = model.indexOf(theme.mode)
|
|
return idx >= 0 ? idx : 0
|
|
}
|
|
onActivated: theme.mode = currentText
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Font ---
|
|
GroupBox {
|
|
title: qsTr("Font")
|
|
Layout.fillWidth: true
|
|
|
|
background: Rectangle {
|
|
color: "transparent"
|
|
border.color: theme.midColor
|
|
border.width: 1
|
|
radius: 4
|
|
y: 12
|
|
}
|
|
|
|
label: Label {
|
|
x: 8
|
|
text: parent.title
|
|
color: theme.textColor
|
|
font.pointSize: theme.fontSize > 0 ? theme.fontSize * 0.9 : 11
|
|
}
|
|
|
|
GridLayout {
|
|
columns: 2
|
|
anchors.fill: parent
|
|
columnSpacing: 12
|
|
rowSpacing: 8
|
|
|
|
Label { text: qsTr("Family:"); color: theme.textColor }
|
|
ComboBox {
|
|
id: fontFamilyCombo
|
|
Layout.fillWidth: true
|
|
model: theme.availableFamilies
|
|
editable: true
|
|
currentIndex: {
|
|
let fam = theme.fontFamily || Qt.application.font.family
|
|
let idx = model.indexOf(fam)
|
|
return idx >= 0 ? idx : 0
|
|
}
|
|
onActivated: theme.fontFamily = currentText
|
|
onAccepted: theme.fontFamily = editText
|
|
}
|
|
|
|
Label { text: qsTr("Style:"); color: theme.textColor }
|
|
ComboBox {
|
|
id: fontStyleCombo
|
|
Layout.fillWidth: true
|
|
model: theme.availableStyles
|
|
currentIndex: {
|
|
let st = theme.fontStyle
|
|
let idx = model.indexOf(st)
|
|
return idx >= 0 ? idx : 0
|
|
}
|
|
onActivated: theme.fontStyle = currentText
|
|
}
|
|
|
|
Label { text: qsTr("Size:"); color: theme.textColor }
|
|
SpinBox {
|
|
id: fontSizeSpin
|
|
from: 6
|
|
to: 72
|
|
value: theme.fontSize > 0 ? theme.fontSize : Qt.application.font.pointSize
|
|
onValueModified: theme.fontSize = value
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- UI Scale ---
|
|
GroupBox {
|
|
title: qsTr("UI Scale")
|
|
Layout.fillWidth: true
|
|
|
|
background: Rectangle {
|
|
color: "transparent"
|
|
border.color: theme.midColor
|
|
border.width: 1
|
|
radius: 4
|
|
y: 12
|
|
}
|
|
|
|
label: Label {
|
|
x: 8
|
|
text: parent.title
|
|
color: theme.textColor
|
|
font.pointSize: theme.fontSize > 0 ? theme.fontSize * 0.9 : 11
|
|
}
|
|
|
|
RowLayout {
|
|
anchors.fill: parent
|
|
spacing: 12
|
|
|
|
Slider {
|
|
id: scaleSlider
|
|
Layout.fillWidth: true
|
|
from: 0.5
|
|
to: 3.0
|
|
stepSize: 0.1
|
|
value: theme.uiScale
|
|
onMoved: theme.uiScale = value
|
|
}
|
|
|
|
Label {
|
|
text: (theme.uiScale * 100).toFixed(0) + "%"
|
|
color: theme.textColor
|
|
Layout.preferredWidth: 50
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Reset buttons ---
|
|
RowLayout {
|
|
Layout.fillWidth: true
|
|
spacing: 8
|
|
|
|
Button {
|
|
text: qsTr("Reset Font")
|
|
onClicked: theme.resetFont()
|
|
}
|
|
|
|
Item { Layout.fillWidth: true }
|
|
}
|
|
}
|
|
}
|
|
}
|