HMI/PropertyEditor/resources/Qml/ValueEditor/FontBox.qml

356 lines
12 KiB
QML
Raw Permalink Normal View History

import QtQuick
import QtQuick.Controls
import QtQuick.Layouts
import ColorPalette
Item {
id: control
property font value
property var fontFamilies: []
property bool expanded: false
property bool internalUpdate: false
property int sizeValue: control.value.pointSize
readonly property int kRowHeight: 25
readonly property int kEditRowCount: 5
readonly property int kExpandedHeight: kRowHeight + kEditRowCount * kRowHeight + (kEditRowCount - 1) * 2
implicitHeight: height
implicitWidth: 100
height: expanded ? kExpandedHeight : kRowHeight
signal asValueChanged(value: var)
function setValue(newValue: var) {
if (internalUpdate) return
if (newValue !== value) {
internalUpdate = true
value = newValue
sizeValue = value.pointSize
internalUpdate = false
asValueChanged(value)
}
}
function applySizeEdit() {
if (control.internalUpdate) return
control.internalUpdate = true
control.value.pointSize = sizeValue
control.internalUpdate = false
control.asValueChanged(control.value)
}
// Header row
Rectangle {
id: headerRow
height: kRowHeight
width: parent.width
color: ColorPalette.theme.textBoxBackground
border.color: expanded ? ColorPalette.theme.comboBoxItemBackgroundHover : ColorPalette.theme.textBoxBackground
border.width: 1
Text {
anchors.fill: parent
anchors.leftMargin: 5
anchors.rightMargin: 20
verticalAlignment: Text.AlignVCenter
text: value.family + ", " + value.pointSize + "pt"
color: ColorPalette.theme.textPrimary
elide: Text.ElideRight
}
Text {
anchors.right: parent.right
anchors.rightMargin: 5
anchors.verticalCenter: parent.verticalCenter
text: expanded ? "▲" : "▼"
color: ColorPalette.theme.labelPrimary
font.pixelSize: 10
}
MouseArea {
anchors.fill: parent
onClicked: control.expanded = !control.expanded
}
}
// Edit pane — 5 rows
Column {
id: editPane
visible: control.expanded
anchors.top: headerRow.bottom
anchors.left: parent.left
anchors.right: parent.right
spacing: 2
// Row 1: Font Family
ComboBox {
id: familyCombo
width: parent.width
height: kRowHeight
model: control.fontFamilies.length > 0 ? control.fontFamilies : []
currentIndex: -1
clip: true
background: Rectangle {
color: ColorPalette.theme.comboBoxBackground
border.color: familyCombo.activeFocus ? ColorPalette.theme.comboBoxItemBackgroundHover : ColorPalette.theme.rowBorder
border.width: 1
}
contentItem: Text {
text: familyCombo.currentIndex >= 0 ? familyCombo.currentText : value.family
color: ColorPalette.theme.textPrimary
verticalAlignment: Text.AlignVCenter
leftPadding: 6
elide: Text.ElideRight
}
popup: Popup {
y: familyCombo.height
width: familyCombo.width
implicitHeight: Math.min(contentItem.contentHeight, 200)
padding: 1
contentItem: ListView {
clip: true
implicitHeight: Math.min(contentHeight, 200)
model: familyCombo.delegateModel
currentIndex: familyCombo.highlightedIndex
ScrollIndicator.vertical: ScrollIndicator {}
}
background: Rectangle {
color: ColorPalette.theme.comboBoxItemBackground
border.color: ColorPalette.theme.rowBorder
}
}
// Sync ComboBox selection when fontFamilies arrives (C++ sets it after value)
function syncComboIndex() {
if (control.fontFamilies.length > 0 && value.family) {
var idx = find(value.family)
if (idx >= 0) currentIndex = idx
}
}
Component.onCompleted: syncComboIndex()
onModelChanged: syncComboIndex()
onActivated: control.applyEdit()
}
// Row 2: Font Size — left spacer aligns "Size" with checkbox text below
RowLayout {
width: parent.width
height: kRowHeight
spacing: 0
// Spacer to align "Size" with checkbox text (indicator 14 + spacing 6 = 20)
Item { Layout.preferredWidth: 20 }
Text {
text: "Size"
color: ColorPalette.theme.labelPrimary
verticalAlignment: Text.AlignVCenter
Layout.preferredWidth: 28
Layout.alignment: Qt.AlignVCenter
}
// Decrease button
Rectangle {
implicitWidth: 22; implicitHeight: kRowHeight
Layout.alignment: Qt.AlignVCenter
color: sizeDownMa.pressed ? ColorPalette.theme.comboBoxItemBackgroundHover : "transparent"
border.color: ColorPalette.theme.rowBorder
border.width: 0.5
Text {
anchors.centerIn: parent
text: ""
font.pixelSize: 12
color: ColorPalette.theme.labelPrimary
}
MouseArea {
id: sizeDownMa
anchors.fill: parent
onClicked: { if (sizeValue > 1) sizeValue--; applySizeEdit() }
}
}
// Number input
Rectangle {
Layout.fillWidth: true
Layout.alignment: Qt.AlignVCenter
implicitHeight: kRowHeight
color: ColorPalette.theme.comboBoxBackground
border.color: sizeInput.activeFocus ? ColorPalette.theme.comboBoxItemBackgroundHover : ColorPalette.theme.rowBorder
border.width: 1
TextInput {
id: sizeInput
anchors.fill: parent
anchors.leftMargin: 4
anchors.rightMargin: 4
color: ColorPalette.theme.textPrimary
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
validator: IntValidator { bottom: 1; top: 512 }
inputMethodHints: Qt.ImhDigitsOnly
text: sizeValue
onEditingFinished: { sizeValue = parseInt(text) || 1; applySizeEdit() }
}
}
// Increase button
Rectangle {
implicitWidth: 22; implicitHeight: kRowHeight
Layout.alignment: Qt.AlignVCenter
color: sizeUpMa.pressed ? ColorPalette.theme.comboBoxItemBackgroundHover : "transparent"
border.color: ColorPalette.theme.rowBorder
border.width: 0.5
Text {
anchors.centerIn: parent
text: "+"
font.pixelSize: 12
color: ColorPalette.theme.labelPrimary
}
MouseArea {
id: sizeUpMa
anchors.fill: parent
onClicked: { if (sizeValue < 512) sizeValue++; applySizeEdit() }
}
}
Text {
text: "pt"
color: ColorPalette.theme.labelPrimary
verticalAlignment: Text.AlignVCenter
Layout.preferredWidth: 20
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 2
}
}
// Row 3: Bold
CheckBox {
id: boldCheck
text: "Bold"
height: kRowHeight
checked: control.value.bold
leftPadding: 0
spacing: 6
indicator: Rectangle {
implicitWidth: 14; implicitHeight: 14
x: boldCheck.leftPadding
y: (boldCheck.height - height) / 2
color: boldCheck.checked ? ColorPalette.theme.comboBoxItemBackgroundHover : "transparent"
border.color: boldCheck.checked ? ColorPalette.theme.comboBoxItemBackgroundHover : ColorPalette.theme.rowBorder
border.width: 1.5
radius: 2
Rectangle {
visible: boldCheck.checked
anchors.centerIn: parent
width: 8; height: 8
color: ColorPalette.theme.labelPrimary
radius: 1
}
}
contentItem: Text {
text: boldCheck.text
color: ColorPalette.theme.textPrimary
verticalAlignment: Text.AlignVCenter
leftPadding: boldCheck.indicator.width + boldCheck.spacing
}
onToggled: control.applyEdit()
}
// Row 4: Italic
CheckBox {
id: italicCheck
text: "Italic"
height: kRowHeight
checked: control.value.italic
leftPadding: 0
spacing: 6
indicator: Rectangle {
implicitWidth: 14; implicitHeight: 14
x: italicCheck.leftPadding
y: (italicCheck.height - height) / 2
color: italicCheck.checked ? ColorPalette.theme.comboBoxItemBackgroundHover : "transparent"
border.color: italicCheck.checked ? ColorPalette.theme.comboBoxItemBackgroundHover : ColorPalette.theme.rowBorder
border.width: 1.5
radius: 2
Rectangle {
visible: italicCheck.checked
anchors.centerIn: parent
width: 8; height: 8
color: ColorPalette.theme.labelPrimary
radius: 1
}
}
contentItem: Text {
text: italicCheck.text
color: ColorPalette.theme.textPrimary
verticalAlignment: Text.AlignVCenter
leftPadding: italicCheck.indicator.width + italicCheck.spacing
}
onToggled: control.applyEdit()
}
// Row 5: Underline
CheckBox {
id: underlineCheck
text: "Underline"
height: kRowHeight
checked: control.value.underline
leftPadding: 0
spacing: 6
indicator: Rectangle {
implicitWidth: 14; implicitHeight: 14
x: underlineCheck.leftPadding
y: (underlineCheck.height - height) / 2
color: underlineCheck.checked ? ColorPalette.theme.comboBoxItemBackgroundHover : "transparent"
border.color: underlineCheck.checked ? ColorPalette.theme.comboBoxItemBackgroundHover : ColorPalette.theme.rowBorder
border.width: 1.5
radius: 2
Rectangle {
visible: underlineCheck.checked
anchors.centerIn: parent
width: 8; height: 8
color: ColorPalette.theme.labelPrimary
radius: 1
}
}
contentItem: Text {
text: underlineCheck.text
color: ColorPalette.theme.textPrimary
verticalAlignment: Text.AlignVCenter
leftPadding: underlineCheck.indicator.width + underlineCheck.spacing
}
onToggled: control.applyEdit()
}
}
function applyEdit() {
if (control.internalUpdate) return
control.internalUpdate = true
control.value = Qt.font({
family: familyCombo.currentText || value.family,
pointSize: sizeValue,
bold: boldCheck.checked,
italic: italicCheck.checked,
underline: underlineCheck.checked
})
control.internalUpdate = false
control.asValueChanged(control.value)
}
}